summaryrefslogtreecommitdiffstats
path: root/lexer.l
diff options
context:
space:
mode:
authorStephen Dolan <mu@netsoc.tcd.ie>2012-09-18 17:44:43 +0100
committerStephen Dolan <mu@netsoc.tcd.ie>2012-09-18 17:44:43 +0100
commita4eea165bbab6d13f89b59707e835d58b7014a66 (patch)
treeb99ee5dde8540f8dbe5de3d87b99e04ac4dd2673 /lexer.l
parent25cbab056b1f73e96b636c88779a92400d92dc15 (diff)
Move everything around - delete old Haskell code, clean up build.
Diffstat (limited to 'lexer.l')
-rw-r--r--lexer.l157
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;
+}