#define _GNU_SOURCE //asprintf #include #include #include #include #include "ast.h" #include "util.h" void ast_free(AST *ast){ assert(ast); switch(ast->type){ case AST_LIST: assert(ast->l.len>=0); for(int i=0;il.len;i++){ assert(ast->l.nodes[i]); ast_free(ast->l.nodes[i]); } break; case AST_WORD: assert(ast->w.word); free(ast->w.word); break; case AST_STRING: assert(ast->S.str); free(ast->S.str); break; case AST_NUMBER: case AST_SYMBOL: break; default: assert(false); } free(ast); } AST* ast_copy(const AST *ast){ assert(ast); switch(ast->type){ case AST_LIST:{ assert(ast->l.len>=0); assert(ast->l.nodes); AST **nodes=malloc(ast->l.len,AST*); for(int i=0;il.len;i++)nodes[i]=ast_copy(ast->l.nodes[i]); AST *l=ast_list(ast->l.len,nodes); l->l.quoted=ast->l.quoted; return l; } case AST_WORD: assert(ast->w.word); return ast_word(copystring(ast->w.word)); 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); sym->s.symid=ast->s.symid; return sym; } default: assert(false); } } 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;il.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;iS.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*)); ast->l.quoted=false; return ast; } 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; }