summaryrefslogtreecommitdiff
path: root/ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'ast.c')
-rw-r--r--ast.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/ast.c b/ast.c
index 8120feb..a6f308d 100644
--- a/ast.c
+++ b/ast.c
@@ -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;