diff options
Diffstat (limited to 'parser.c')
-rw-r--r-- | parser.c | 68 |
1 files changed, 59 insertions, 9 deletions
@@ -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); } } |