/* Copyright 2009-2016 * Kaz Kylheku * Vancouver, Canada * All rights reserved. * * Redistribution of this software in source and binary forms, with or without * modification, is permitted provided that the following two conditions are met. * * Use of this software in any manner constitutes agreement with the disclaimer * which follows the two conditions. * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DAMAGES, HOWEVER CAUSED, * AND UNDER ANY THEORY OF LIABILITY, ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ %{ #include #include #include #include #include #include #include #include #include #include #include "config.h" #if HAVE_UNISTD_H #include #endif #include "lib.h" #include "gc.h" #include "stream.h" #include "utf8.h" #include "signal.h" #include "unwind.h" #include "hash.h" #include "y.tab.h" #include "parser.h" #include "eval.h" #include "txr.h" #define YY_INPUT(buf, result, max_size) \ do { \ val c = get_byte(yyextra->stream); \ int n = 0; \ if (c) \ buf[n++] = convert(char, c_num(c)); \ result = n; \ } while (0) #define YY_DECL \ static int yylex_impl(YYSTYPE *yylval_param, yyscan_t yyscanner) int opt_loglevel = 1; /* 0 - quiet; 1 - normal; 2 - verbose */ val form_to_ln_hash; #define FLEX_NUM_VERSION 10000*YY_FLEX_MAJOR_VERSION + \ 100*YY_FLEX_MINOR_VERSION + \ YY_FLEX_SUBMINOR_VERSION #if FLEX_NUM_VERSION < 20509 int yylex_destroy(void) { return 0; } #endif /* Missing prototypes not generated by flex. */ int yyget_column(yyscan_t); void yyset_column (int column_no, yyscan_t yyscanner); /* The following function is all that libflex provides. By providing it here, we eliminate the need to link libflex. */ #define YY_SKIP_YYWRAP INLINE int yywrap(yyscan_t scanner) { (void) scanner; return 1; } void yyerror(scanner_t *scanner, parser_t *parser, const char *s) { yyerrorf(scanner, lit("~a"), string_utf8(s), nao); if (parser->prepared_msg) { yyerrorf(scanner, lit("~a"), parser->prepared_msg, nao); parser->prepared_msg = nil; } } void yyerrorf(scanner_t *scanner, val fmt, ...) { parser_t *parser = yyget_extra(scanner); if (opt_loglevel >= 1) { va_list vl; va_start (vl, fmt); if (opt_compat && opt_compat <= 114) format(std_error, lit("~a: (~a:~d): "), prog_string, parser->name, num(parser->lineno), nao); else format(std_error, lit("~a:~d: "), parser->name, num(parser->lineno), nao); vformat(std_error, fmt, vl); put_char(chr('\n'), std_error); va_end (vl); } parser->errors++; } static void yyerrprepf(scanner_t *scanner, val fmt, ...) { parser_t *parser = yyget_extra(scanner); if (opt_loglevel >= 1) { va_list vl; va_start (vl, fmt); set(mkloc(parser->prepared_msg, parser->parser), vformat_to_string(fmt, vl)); va_end (vl); } } static wchar_t char_esc(int letter) { switch (letter) { case ' ': return L' '; case 'a': return L'\a'; case 'b': return L'\b'; case 't': return L'\t'; case 'n': return L'\n'; case 'v': return L'\v'; case 'f': return L'\f'; case 'r': return L'\r'; case 'e': return 27; case '"': return L'"'; case '\'': return L'\''; case '`': return L'`'; case '/': return L'/'; case '@': return L'@'; case '\\': return L'\\'; } internal_error("unhandled escape character"); } static wchar_t num_esc(scanner_t *scn, char *num) { if (num[0] == 'x') { if (strlen(num) > 7) yyerror(scn, yyget_extra(scn), "too many digits in hex character escape"); return strtol(num + 1, 0, 16); } else { if (num[0] == 'o') num++; if (strlen(num) > 8) yyerror(scn, yyget_extra(scn), "too many digits in octal character escape"); return strtol(num, 0, 8); } } %} %option stack noinput reentrant bison-bridge extra-type="parser_t *" SYM [a-zA-Z0-9_]+ SGN [+\-] EXP [eE][+\-]?[0-9]+ DIG [0-9] XDIG [0-9A-Fa-f] NUM {SGN}?{DIG}+ FLO {SGN}?({DIG}*[.]{DIG}+{EXP}?|{DIG}+[.]?{EXP}) FLODOT {SGN}?{DIG}+[.] DOTFLO [.]{DIG}+ XNUM #x{SGN}?{XDIG}+ ONUM #o{SGN}?[0-7]+ BNUM #b{SGN}?[0-1]+ BSCHR [a-zA-Z0-9!$%&*+\-<=>?\\_~] NSCHR [a-zA-Z0-9!$%&*+\-<=>?\\_~/] ID_END [^a-zA-Z0-9!$%&*+\-<=>?\\_~/] EXTRA [#^] TOK {SYM} BT0 {BSCHR}({BSCHR}|{EXTRA})* BT1 @{BT0}+ BT2 ({BSCHR}|{EXTRA})+ BTREG ({BT0}|{BT1})?:{BT2}?|({BT0}|{BT1})(:{BT2})? BTKEY @?:{BT2}? BTOK {BTREG}|{BTKEY} NT0 {NSCHR}({NSCHR}|{EXTRA})* NT1 @{NT0}+ NT2 ({NSCHR}|{EXTRA})+ NTREG ({NT0}|{NT1})?:{NT2}?|({NT0}|{NT1})(:{NT2})? NTKEY @?:{NT2}? NTOK {NTREG}|{NTKEY} WS [\t ]* REQWS [\t ]+ NL (\n|\r|\r\n) HEX [0-9A-Fa-f] OCT [0-7] REGOP [/()|.*?+~&%\[\]\-] ASC [\x00-\x7f] ASCN [\x00-\t\v-\x7f] U [\x80-\xbf] U2 [\xc2-\xdf] U3 [\xe0-\xef] U4 [\xf0-\xf4] UANY {ASC}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} UANYN {ASCN}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} %x SPECIAL BRACED NESTED REGEX SREGEX STRLIT CHRLIT QSILIT QSPECIAL WLIT QWLIT %% {NUM} { val str = string_own(utf8_dup_from(yytext)); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->val = int_str(str, num(10)); return NUMBER; } ({XNUM}|{ONUM}|{BNUM}) { val str = string_own(utf8_dup_from(yytext + 2)); int base; switch (yytext[1]) { case 'x': base = 16; break; case 'o': base = 8; break; case 'b': default: base = 2; break; } if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->val = int_str(str, num_fast(base)); return NUMBER; } ({BNUM}|{ONUM}|{XNUM}){TOK} { int base = 0; val str = string_own(utf8_dup_from(yytext + 2)); switch (yytext[1]) { case 'x': base = 16; break; case 'o': base = 8; break; case 'b': default: base = 2; break; } yyerrorf(yyg, lit("trailing junk in numeric literal: ~a~a~a"), chr(yytext[0]), chr(yytext[1]), str, nao); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->val = int_str(str, num_fast(base)); return NUMBER; } {FLO} { val str = string_own(utf8_dup_from(yytext)); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->val = flo_str(str); return NUMBER; } ({FLO}|{FLODOT}){TOK} | ({FLO}|{FLODOT}){BTOK} | ({FLO}|{FLODOT}){NTOK} { val str = string_utf8(yytext); yyerrorf(yyg, lit("trailing junk in floating-point literal: ~a"), str, nao); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->val = flo_str(str); return NUMBER; } {FLODOT}/[^.] { val str = string_own(utf8_dup_from(yytext)); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->val = flo_str(str); return NUMBER; } @{NUM} { val str = string_own(utf8_dup_from(yytext + 1)); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->val = int_str(str, num(10)); return METANUM; } @{XNUM} { val str = string_own(utf8_dup_from(yytext + 3)); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->val = int_str(str, num(16)); return METANUM; } @{ONUM} { val str = string_own(utf8_dup_from(yytext + 3)); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->val = int_str(str, num(8)); return METANUM; } @{BNUM} { val str = string_own(utf8_dup_from(yytext + 3)); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->val = int_str(str, num(2)); return METANUM; } {TOK}/{DOTFLO} | {BTOK}/{DOTFLO} | {NTOK}/{DOTFLO} { printf("yytext: %s\n", yytext); yyerrorf(yyg, lit("cramped floating-point literal: " "space needed between ~a and dot."), string_own(utf8_dup_from(yytext)), nao); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->lexeme = utf8_dup_from(yytext); return SYMTOK; } {TOK} | {BTOK} | {NTOK} { if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); yylval->lexeme = utf8_dup_from(yytext); return SYMTOK; } \({WS}all{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return ALL; } \({WS}some/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return SOME; } \({WS}none{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return NONE; } \({WS}maybe{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return MAYBE; } \({WS}cases{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return CASES; } \({WS}block/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return BLOCK; } \({WS}choose/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return CHOOSE; } \({WS}gather/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return GATHER; } \({WS}and{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return AND; } \({WS}or{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return OR; } \({WS}end{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return END; } \({WS}collect/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return COLLECT; } \({WS}coll/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return COLL; } \({WS}until/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return UNTIL; } \({WS}output/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return OUTPUT; } \({WS}repeat/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return REPEAT; } \({WS}rep/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return REP; } \({WS}single{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return SINGLE; } \({WS}first{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return FIRST; } \({WS}last/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return LAST; } \({WS}empty{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return EMPTY; } \({WS}mod/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return MOD; } \({WS}modlast/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return MODLAST; } \({WS}define/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return DEFINE; } \({WS}try{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return TRY; } \({WS}catch/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return CATCH; } \({WS}finally{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return FINALLY; } \({WS}if/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return IF; } \({WS}elif/{ID_END} { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return ELIF; } \({WS}else{WS}\) { yy_pop_state(yyscanner); yylval->lineno = yyextra->lineno; return ELSE; } [{] { yy_push_state(BRACED, yyscanner); yylval->lineno = yyextra->lineno; return yytext[0]; } [(\[] { yy_push_state(NESTED, yyscanner); yylval->lineno = yyextra->lineno; return yytext[0]; } @ { yylval->lineno = yyextra->lineno; return yytext[0]; } ,[*] { yylval->chr = '*'; return SPLICE; } [,'^] { yylval->chr = yytext[0]; return yytext[0]; } [}] { yy_pop_state(yyscanner); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); return yytext[0]; } [)\]]/{DOTFLO} { yyerrorf(yyg, lit("cramped floating-point literal: " "space or 0 needed between ~a and dot."), string_own(utf8_dup_from(yytext)), nao); yy_pop_state(yyscanner); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); return yytext[0]; } [)\]] { yy_pop_state(yyscanner); if (yy_top_state(yyscanner) == INITIAL || yy_top_state(yyscanner) == QSILIT || yy_top_state(yyscanner) == QWLIT) yy_pop_state(yyscanner); return yytext[0]; } {WS} { /* Eat whitespace in directive */ } \" { yy_push_state(STRLIT, yyscanner); return '"'; } #\\ { yy_push_state(CHRLIT, yyscanner); return HASH_BACKSLASH; } #[/] { yy_push_state(REGEX, yyscanner); return HASH_SLASH; } ` { yy_push_state(QSILIT, yyscanner); return '`'; } #\" { yy_push_state(WLIT, yyscanner); return WORDS; } #\*\" { yy_push_state(WLIT, yyscanner); return WSPLICE; } #\` { yy_push_state(QWLIT, yyscanner); return QWORDS; } #\*\` { yy_push_state(QWLIT, yyscanner); return QWSPLICE; } # { return '#'; } #H { yylval->lineno = yyextra->lineno; return HASH_H; } #S { yylval->lineno = yyextra->lineno; return HASH_S; } #R { yylval->lineno = yyextra->lineno; return HASH_R; } \.\. { yylval->lineno = yyextra->lineno; return DOTDOT; } @ { yy_pop_state(yyscanner); yylval->lexeme = chk_strdup(L"@"); return TEXT; } {NL} { yyextra->lineno++; } [/] { yy_push_state(REGEX, yyscanner); return '/'; } {REQWS}\.{REQWS} { yylval->chr = '.'; return CONSDOT; } \.{REQWS} { yylval->chr = '.'; return LAMBDOT; } \. { yylval->chr = '.'; return '.'; } [\\]{NL}{WS} { if (YYSTATE == SPECIAL) yy_pop_state(yyscanner); /* @\ continuation */ yyextra->lineno++; } [\\][abtnvfre ] { wchar_t lexeme[2]; lexeme[0] = char_esc(yytext[1]); lexeme[1] = 0; yylval->lexeme = chk_strdup(lexeme); yy_pop_state(yyscanner); return TEXT; } [\\](x{HEX}+|{OCT}+);? { wchar_t lexeme[2]; lexeme[0] = num_esc(yyg, yytext + 1); lexeme[1] = 0; yylval->lexeme = chk_strdup(lexeme); { char lastchar = yytext[yyleng-1]; if (lastchar == ';' && opt_compat && opt_compat <= 109) unput(lastchar); } yy_pop_state(yyscanner); return TEXT; } [\\]. { yyerrorf(yyg, lit("unrecognized escape \\~a"), chr(yytext[1]), nao); } [;][^\n\r]* { /* comment */ } {UANYN} { val ch = chr_str(string_utf8(yytext), zero); if (chr_isspace(ch)) yyerrprepf(yyg, lit("unexpected whitespace character #\\x~02x"), ch, nao); else if (chr_isunisp(ch)) yyerrprepf(yyg, lit("unexpected Unicode space character #\\x~02x"), ch, nao); else if (chr_iscntrl(ch)) yyerrprepf(yyg, lit("unexpected control character #\\x~02x"), ch, nao); else yyerrprepf(yyg, lit("unexpected character #\\~a"), ch, nao); return ERRTOK; } . { yyerrprepf(yyg, lit("non-UTF-8 byte #x~02x in directive"), num(convert(unsigned char, yytext[0])), nao); return ERRTOK; } [/] { yylval->chr = '/'; return (YYSTATE == SREGEX) ? REGCHAR : '/'; } [\\][abtnvfre\\ ] { yylval->chr = char_esc(yytext[1]); return REGCHAR; } [\\](x{HEX}+|{OCT}+);? { yylval->chr = num_esc(yyg, yytext + 1); return REGCHAR; } [\\][sSdDwW] { yylval->chr = yytext[1]; return REGTOKEN; } {WS}[\\]{NL}{WS} { yyextra->lineno++; } {NL} { yyextra->lineno++; yyerrprepf(yyg, lit("newline in regex"), nao); return ERRTOK; } {REGOP} { yylval->chr = yytext[0]; return yytext[0]; } [\\]{REGOP} { yylval->chr = yytext[1]; return REGCHAR; } [\\]. { if (opt_compat && opt_compat <= 105) { yylval->chr = yytext[1]; return REGCHAR; } yyerrprepf(yyg, lit("unrecognized escape in regex"), nao); return ERRTOK; } [\\] { yyerrprepf(yyg, lit("dangling backslash in regex"), nao); return ERRTOK; } {UANYN} { wchar_t buf[8]; utf8_from(buf, yytext); yylval->chr = buf[0]; return REGCHAR; } . { yyerrprepf(yyg, lit("non-UTF-8 byte in regex: '\\x~02x'"), num(convert(unsigned char, yytext[0])), nao); return ERRTOK; } [ ]+ { yylval->lexeme = utf8_dup_from(yytext); return SPACE; } ({UONLY}|[^@\n\r ])+ { yylval->lexeme = utf8_dup_from(yytext); return TEXT; } {NL} { yyextra->lineno++; return '\n'; } @{WS}\* { yy_push_state(SPECIAL, yyscanner); return '*'; } @ { yy_push_state(SPECIAL, yyscanner); } ^@[#;].*{NL} { /* eat whole line comment */ yyextra->lineno++; } @[#;].* { /* comment to end of line */ } \" { yy_pop_state(yyscanner); return yytext[0]; } \` { yy_pop_state(yyscanner); return yytext[0]; } [\\][abtnvfre "`'\\ ] { yylval->chr = char_esc(yytext[1]); return LITCHAR; } [\\]@ { yylval->chr = char_esc(yytext[1]); return LITCHAR; } {WS}[\\]{NL}{WS} { yyextra->lineno++; } {WS}[\\]{NL}{WS} { yyextra->lineno++; if (!opt_compat || opt_compat > 109) return ' '; } [\\](x{HEX}+|{OCT}+);? { yylval->chr = num_esc(yyg, yytext+1); return LITCHAR; } [\\]. { yyerrorf(yyg, lit("unrecognized escape: \\~a"), chr(yytext[1]), nao); } (x{HEX}+|o{OCT}+) { yylval->chr = num_esc(yyg, yytext); return LITCHAR; } {SYM} { yylval->lexeme = utf8_dup_from(yytext); return SYMTOK; } [^ \t\n\r] { yylval->lexeme = utf8_dup_from(yytext); return SYMTOK; /* hack */ } {NL} { yyerrprepf(yyg, lit("newline in string literal"), nao); yyextra->lineno++; yylval->chr = yytext[0]; return ERRTOK; } {NL} { yyerrprepf(yyg, lit("newline in character literal"), nao); yyextra->lineno++; yylval->chr = yytext[0]; return ERRTOK; } {NL} { yyerrprepf(yyg, lit("newline in string quasiliteral"), nao); yyextra->lineno++; yylval->chr = yytext[0]; return ERRTOK; } {NL} { yyextra->lineno++; if (opt_compat && opt_compat <= 109) return ' '; yyerrprepf(yyg, lit("newline in word list literal"), nao); yylval->chr = yytext[0]; return ERRTOK; } @/([[({'^,@]|{TOK}) { yy_push_state(QSPECIAL, yyscanner); return yytext[0]; } @ { yyerrprepf(yyg, lit("malformed @ expression in quasiliteral"), nao); return ERRTOK; } {WS} { return ' '; } {UANYN} { wchar_t buf[8]; utf8_from(buf, yytext); yylval->chr = buf[0]; return LITCHAR; } . { yyerrprepf(yyg, lit("non-UTF-8 byte in literal: '\\x~02x'"), num(convert(unsigned char, yytext[0])), nao); return ERRTOK; } %% void end_of_regex(scanner_t *yyg) { if (YYSTATE != REGEX && YYSTATE != SREGEX) internal_error("end_of_regex called in wrong scanner state"); yy_pop_state(yyg); if (YYSTATE != INITIAL) { if (yy_top_state(yyg) == INITIAL || yy_top_state(yyg) == QSILIT || yy_top_state(yyg) == QWLIT) yy_pop_state(yyg); } } void end_of_char(scanner_t *yyg) { if (YYSTATE != CHRLIT) internal_error("end_of_char called in wrong scanner state"); yy_pop_state(yyg); } val source_loc(val form) { return gethash(form_to_ln_hash, form); } val source_loc_str(val form, val alt) { cons_bind (line, file, gethash(form_to_ln_hash, form)); if (missingp(alt)) alt = lit("source location n/a"); return if3(line, format(nil, lit("~a:~d"), file, line, nao), alt); } int yylex(YYSTYPE *yylval_param, yyscan_t yyscanner) { struct yyguts_t * yyg = convert(struct yyguts_t *, yyscanner); int yy_char; if (yyextra->tok_idx > 0) { struct yy_token *tok = &yyextra->tok_pushback[--yyextra->tok_idx]; yyextra->recent_tok = *tok; *yylval_param = tok->yy_lval; return tok->yy_char; } yy_char = yyextra->recent_tok.yy_char = yylex_impl(yylval_param, yyscanner); yyextra->recent_tok.yy_lval = *yylval_param; return yy_char; } void prime_scanner(scanner_t *yyg, enum prime_parser prim) { while (YYSTATE != INITIAL) yy_pop_state(yyg); switch (prim) { case prime_lisp: case prime_interactive: yy_push_state(SPECIAL, yyg); yy_push_state(NESTED, yyg); yy_push_state(NESTED, yyg); break; case prime_regex: yy_push_state(SREGEX, yyg); break; } } void scrub_scanner(scanner_t *yyg, int yy_char, wchar_t *lexeme) { struct yy_token *rtok = &yyextra->recent_tok; if (rtok->yy_char == yy_char && rtok->yy_lval.lexeme == lexeme) { rtok->yy_char = 0; rtok->yy_lval.lexeme = 0; } } void parser_l_init(void) { prot1(&form_to_ln_hash); form_to_ln_hash = make_hash(t, nil, nil); }