summaryrefslogtreecommitdiff
path: root/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'parser.c')
-rw-r--r--parser.c68
1 files changed, 59 insertions, 9 deletions
diff --git a/parser.c b/parser.c
index 5069904..d91af7e 100644
--- a/parser.c
+++ b/parser.c
@@ -75,13 +75,14 @@ static Token nexttoken(Cursor *cursor){
if(*cursor->s=='"'){
int i;
- for(i=0;i<cursor->l;i++){
+ for(i=1;i<cursor->l;i++){
if(cursor->s[i]=='"')break;
if(cursor->s[i]=='\\')i++;
}
if(i==cursor->l){
return tt_err("Unclosed string in source");
}
+ i++;
advance(cursor,i);
return tt_make(TT_STRING,cursor->s-i,i);
}
@@ -107,6 +108,15 @@ static Token nexttoken(Cursor *cursor){
}
+static bool ishexdigit(char c){
+ return (c>='0'&&c<='9')||(c>='a'&&c<='f')||(c>='A'&&c<='F');
+}
+
+static int hexnum(char c){
+ return c<='9'?c-'0':(c&~32)-'A';
+}
+
+
static ParseRet pr_ast(AST *ast){
ParseRet pr={ast,NULL};
return pr;
@@ -164,23 +174,63 @@ static ParseRet parse_(Cursor *cursor){
nodes[len++]=pr.ast;
}
return pr_ast(ast_list(len,nodes));
- break;
}
case TT_WORD:
- break;
+ return pr_ast(ast_word(copybufasstring(tok.str,tok.len)));
case TT_QUOTEDWORD:
- break;
+ return pr_ast(ast_symbol(copybufasstring(tok.str,tok.len)));
case TT_NUMBER:
- break;
-
- case TT_STRING:
- break;
+ return pr_ast(ast_number(strtod(tok.str,NULL)));
+
+ case TT_STRING:{
+ assert(tok.len>=2&&tok.str[0]=='"'&&tok.str[tok.len-1]=='"');
+ int len=0;
+ for(int i=1;i<tok.len-1;i++){
+ if(tok.str[i]=='\\'){
+ i++;
+ assert(i<tok.len-1);
+ if(tok.str[i]=='x'){
+ if(i>=tok.len-3||!ishexdigit(tok.str[i+1])||!ishexdigit(tok.str[i+2])){
+ return pr_err_c("\"\\x\" in string needs two hexadecimal digits");
+ }
+ i+=2;
+ }
+ }
+ len++;
+ }
+ char *buf=malloc(len==0?1:len,char);
+ int j=0;
+ for(int i=1;i<tok.len-1;i++){
+ if(tok.str[i]=='\\'){
+ i++;
+ switch(tok.str[i]){
+ case 'x':
+ buf[j++]=16*hexnum(tok.str[i+1])+hexnum(tok.str[i+2]);
+ i+=2;
+ break;
+
+ case 'n': buf[j++]='\n'; break;
+ case 't': buf[j++]='\t'; break;
+ case 'r': buf[j++]='\r'; break;
+ case 'b': buf[j++]='\b'; break;
+ case 'a': buf[j++]='\a'; break;
+ default: buf[j++]=tok.str[i]; break;
+ }
+ } else {
+ buf[j++]=tok.str[i];
+ }
+ }
+ return pr_ast(ast_string(buf,len));
+ }
case TT_ERR:
- break;
+ return pr_err_c(tok.str);
+
+ default:
+ assert(false);
}
}