diff options
Diffstat (limited to 'ast.c')
-rw-r--r-- | ast.c | 126 |
1 files changed, 126 insertions, 0 deletions
@@ -1,3 +1,5 @@ +#define _GNU_SOURCE //asprintf +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> @@ -22,6 +24,11 @@ void ast_free(AST *ast){ free(ast->w.word); break; + case AST_STRING: + assert(ast->S.str); + free(ast->S.str); + break; + case AST_NUMBER: case AST_SYMBOL: break; @@ -53,6 +60,9 @@ AST* ast_copy(const AST *ast){ case AST_NUMBER: return ast_number(ast->n.num); + case AST_STRING: + return ast_string(copybufasstring(ast->S.str,ast->S.len),ast->S.len); + case AST_SYMBOL:{ assert(ast->s.name); AST *sym=ast_symbol(ast->s.name); @@ -66,10 +76,115 @@ AST* ast_copy(const AST *ast){ } +typedef struct Buffer{ + char *buf; + int sz,len; +} Buffer; + +static Buffer buf_make(int capacity){ + assert(capacity>0); + Buffer buf={malloc(capacity,char),capacity,0}; + buf.buf[0]='\0'; + return buf; +} + +static void buf_append(Buffer *buf,const char *str,int len){ + assert(buf); + assert(str); + assert(len>=0); + if(len==0)return; + if(buf->len+len>buf->sz-1){ + do buf->sz*=2; + while(buf->len+len>buf->sz-1); + buf->buf=realloc(buf->buf,buf->sz,char); + } + memcpy(buf->buf+buf->len,str,len); + buf->len+=len; + buf->buf[buf->len]='\0'; +} + +static char hexchar(int n){ + assert(n>=0&&n<16); + if(n<10)return n+'0'; + return n-10+'a'; +} + +static void ast_stringify_(const AST *ast,Buffer *buf){ + assert(ast); + assert(buf); + switch(ast->type){ + case AST_LIST: + if(ast->l.quoted)buf_append(buf,"'",1); + buf_append(buf,"(",1); + for(int i=0;i<ast->l.len;i++){ + if(i!=0)buf_append(buf," ",1); + ast_stringify_(ast->l.nodes[i],buf); + } + buf_append(buf,")",1); + break; + + case AST_WORD: + buf_append(buf,ast->w.word,strlen(ast->w.word)); + break; + + case AST_NUMBER:{ + char *s; + int len=asprintf(&s,"%g",ast->n.num); + if(!s)outofmem(); + buf_append(buf,s,len); + free(s); + break; + } + + case AST_STRING:{ + buf_append(buf,"\"",1); + const char *str=ast->S.str; + for(int i=0;i<ast->S.len;i++){ + if(str[i]>=32&&str[i]<=126)buf_append(buf,str+i,1); + else switch(str[i]){ + case '\n': buf_append(buf,"\\n",2); break; + case '\t': buf_append(buf,"\\t",2); break; + case '\r': buf_append(buf,"\\r",2); break; + case '\b': buf_append(buf,"\\b",2); break; + case '\a': buf_append(buf,"\\a",2); break; + default:{ + char hexbuf[4]; + hexbuf[0]='\\'; + hexbuf[1]='x'; + hexbuf[2]=hexchar((unsigned char)str[i]/16); + hexbuf[3]=hexchar((unsigned char)str[i]%16); + buf_append(buf,hexbuf,4); + break; + } + } + } + buf_append(buf,"\"",1); + break; + } + + case AST_SYMBOL: + buf_append(buf,"'",1); + buf_append(buf,ast->s.name,strlen(ast->s.name)); + break; + + default: + assert(false); + } +} + +char* ast_stringify(const AST *ast){ + assert(ast); + Buffer buf=buf_make(32); + ast_stringify_(ast,&buf); + return buf.buf; +} + + AST* ast_list(int len,AST **nodes){ assert(len>=0); assert(nodes); AST *ast=malloc(1,AST); + ast->type=AST_LIST; ast->l.len=len; ast->l.nodes=malloc(len,AST*); memcpy(ast->l.nodes,nodes,len*sizeof(AST*)); @@ -80,19 +195,30 @@ AST* ast_list(int len,AST **nodes){ AST* ast_word(char *word){ assert(word); AST *ast=malloc(1,AST); + ast->type=AST_WORD; ast->w.word=word; return ast; } AST* ast_number(double num){ AST *ast=malloc(1,AST); + ast->type=AST_NUMBER; ast->n.num=num; return ast; } +AST* ast_string(char *str,int len){ + AST *ast=malloc(1,AST); + ast->type=AST_STRING; + ast->S.str=str; + ast->S.len=len; + return ast; +} + AST* ast_symbol(char *name){ assert(name); AST *ast=malloc(1,AST); + ast->type=AST_SYMBOL; ast->s.name=name; ast->s.symid=-1; return ast; |