diff options
author | Stephen Dolan <mu@netsoc.tcd.ie> | 2012-09-18 17:44:43 +0100 |
---|---|---|
committer | Stephen Dolan <mu@netsoc.tcd.ie> | 2012-09-18 17:44:43 +0100 |
commit | a4eea165bbab6d13f89b59707e835d58b7014a66 (patch) | |
tree | b99ee5dde8540f8dbe5de3d87b99e04ac4dd2673 /lexer.l | |
parent | 25cbab056b1f73e96b636c88779a92400d92dc15 (diff) |
Move everything around - delete old Haskell code, clean up build.
Diffstat (limited to 'lexer.l')
-rw-r--r-- | lexer.l | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/lexer.l b/lexer.l new file mode 100644 index 00000000..e604adab --- /dev/null +++ b/lexer.l @@ -0,0 +1,157 @@ +%{ +#include "compile.h" +#include "parser.gen.h" /* Generated by bison. */ + +#define YY_USER_ACTION \ + do { \ + yylloc->start = yyget_extra(yyscanner); \ + yylloc->end = yylloc->start + yyleng; \ + yyset_extra(yylloc->end, yyscanner); \ + } while (0); + +%} + +%s IN_PAREN +%s IN_BRACKET +%s IN_BRACE +%s IN_QQINTERP +%x IN_QQSTRING +%{ + static int enter(int opening, int state, yyscan_t yyscanner); + static int try_exit(int closing, int state, yyscan_t yyscanner); +%} + +%option noyywrap nounput noinput nodefault +%option reentrant +%option extra-type="int" +%option bison-bridge bison-locations +%option prefix="jq_yy" +%option stack + + +%% + +"==" { return EQ; } +"as" { return AS; } +"def" { return DEF; } +"if" { return IF; } +"then" { return THEN; } +"else" { return ELSE; } +"elif" { return ELSE_IF; } +"and" { return AND; } +"or" { return OR; } +"end" { return END; } +"//" { return DEFINEDOR; } +"|=" { return SETPIPE; } +"+=" { return SETPLUS; } +"-=" { return SETMINUS; } +"*=" { return SETMULT; } +"/=" { return SETDIV; } +"//=" { return SETDEFINEDOR; } +"."|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"\$" { return yytext[0];} + +"["|"{"|"(" { + return enter(yytext[0], YY_START, yyscanner); +} + +"]"|"}"|")" { + return try_exit(yytext[0], YY_START, yyscanner); +} + + +\"(\\.|[^\\\"])*\" | +-?[0-9.]+([eE][+-]?[0-9]+)? { + yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL; +} + +\"(\\.|[^\\\"])* { + yylval->literal = jv_invalid_with_msg(jv_string("Unterminated string")); + return LITERAL; +} + +"@(" { + yy_push_state(IN_QQSTRING, yyscanner); + return QQSTRING_START; +} + +<IN_QQSTRING>{ + "%(" { + return enter(QQSTRING_INTERP_START, YY_START, yyscanner); + } + "%"[^(] { + return INVALID_CHARACTER; + } + ")" { + yy_pop_state(yyscanner); + return QQSTRING_END; + } + "\\"[)%] { + char text[2] = {yytext[1], 0}; + yylval->literal = jv_string(text); + return QQSTRING_TEXT; + } + (\\[^u)%]|\\u[a-zA-Z0-9]{0,4})+ { + /* pass escapes to the json parser */ + jv escapes = jv_string_fmt("\"%.*s\"", yyleng, yytext); + yylval->literal = jv_parse_sized(jv_string_value(escapes), jv_string_length(jv_copy(escapes))); + jv_free(escapes); + return QQSTRING_TEXT; + } + [^\\)%]+ { + yylval->literal = jv_string_sized(yytext, yyleng); + return QQSTRING_TEXT; + } + . { + return INVALID_CHARACTER; + } +} + + +[[:alnum:]]+ { yylval->literal = jv_string(yytext); return IDENT;} + +[ \n\t]+ {} + +. { return INVALID_CHARACTER; } + +%% +/* perhaps these should be calls... */ +/* +"true" { return TRUE; } +"false" { return FALSE; } +"null" { return NULL; } +*/ +static int try_exit(int c, int state, yyscan_t yyscanner) { + char match = 0; + int ret; + switch (state) { + case IN_PAREN: match = ret = ')'; break; + case IN_BRACKET: match = ret = ']'; break; + case IN_BRACE: match = ret = '}'; break; + + case IN_QQINTERP: + match = ')'; + ret = QQSTRING_INTERP_END; + break; + } + assert(match); + if (match == c) { + yy_pop_state(yyscanner); + return ret; + } else { + // FIXME: should we pop? Give a better error at least + return INVALID_CHARACTER; + } +} + +static int enter(int c, int currstate, yyscan_t yyscanner) { + int state = 0; + switch (c) { + case '(': state = IN_PAREN; break; + case '[': state = IN_BRACKET; break; + case '{': state = IN_BRACE; break; + case QQSTRING_INTERP_START: state = IN_QQINTERP; break; + } + assert(state); + yy_push_state(state, yyscanner); + return c; +} |