]> granicus.if.org Git - re2c/commitdiff
Fixed some more out of bounds reads in lexer due to not handling EOF properly.
authorUlya Trofimovich <skvadrik@gmail.com>
Tue, 30 Oct 2018 22:11:32 +0000 (22:11 +0000)
committerUlya Trofimovich <skvadrik@gmail.com>
Tue, 30 Oct 2018 22:11:32 +0000 (22:11 +0000)
Found by american fuzzy lop (thanks to Henri Salo).

re2c/bootstrap/src/ast/lex.cc
re2c/src/ast/lex.re
re2c/src/ast/scanner.h
re2c/test/american_fuzzy_lop/001.c [new file with mode: 0644]
re2c/test/american_fuzzy_lop/001.re [moved from re2c/test/american_fuzzy_lop/01.re with 100% similarity]
re2c/test/american_fuzzy_lop/002.c [new file with mode: 0644]
re2c/test/american_fuzzy_lop/002.re [new file with mode: 0644]
re2c/test/american_fuzzy_lop/003.c [new file with mode: 0644]
re2c/test/american_fuzzy_lop/003.re [new file with mode: 0644]
re2c/test/american_fuzzy_lop/01.c [deleted file]
re2c/test/bug1529351.c

index bf86f93eb5697b0935751e192eec28ecf14ccd9e..6c6f337c02d980751145285302818130aa35c4c8 100644 (file)
@@ -1,4 +1,4 @@
-/* Generated by re2c 1.1.1 on Mon Oct 29 23:15:19 2018 */
+/* Generated by re2c 1.1.1 on Tue Oct 30 22:03:15 2018 */
 #line 1 "../src/ast/lex.re"
 #include "src/util/c99_stdint.h"
 #include <stddef.h>
@@ -38,7 +38,7 @@ namespace re2c
 #line 38 "../src/ast/lex.re"
 
 
-#line 59 "../src/ast/lex.re"
+#line 60 "../src/ast/lex.re"
 
 
 Scanner::ParseMode Scanner::echo(OutputFile &out)
@@ -111,7 +111,7 @@ echo:
                }
        }
        ++YYCURSOR;
-#line 136 "../src/ast/lex.re"
+#line 137 "../src/ast/lex.re"
        {
         if (cur != eof) goto echo;
         out.wraw(tok, ptr);
@@ -121,7 +121,7 @@ echo:
 yy4:
        ++YYCURSOR;
 yy5:
-#line 154 "../src/ast/lex.re"
+#line 155 "../src/ast/lex.re"
        { goto echo; }
 #line 127 "src/ast/lex.cc"
 yy6:
@@ -132,7 +132,7 @@ yy6:
        }
        if (yych == '#') goto yy14;
 yy7:
-#line 148 "../src/ast/lex.re"
+#line 149 "../src/ast/lex.re"
        {
         cline++;
         pos = cur;
@@ -181,7 +181,7 @@ yy14:
        }
 yy16:
        ++YYCURSOR;
-#line 73 "../src/ast/lex.re"
+#line 74 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr);
         return Parse;
@@ -444,7 +444,7 @@ yy71:
 yy73:
        ++YYCURSOR;
        YYCURSOR = YYCTXMARKER;
-#line 142 "../src/ast/lex.re"
+#line 143 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr + 1);
         set_sourceline();
@@ -559,7 +559,7 @@ yy99:
        goto yy13;
 yy100:
        ++YYCURSOR;
-#line 94 "../src/ast/lex.re"
+#line 95 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr);
         out.wdelay_yymaxfill();
@@ -589,7 +589,7 @@ yy106:
        goto yy13;
 yy107:
        ++YYCURSOR;
-#line 83 "../src/ast/lex.re"
+#line 84 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr);
         return Reuse;
@@ -637,7 +637,7 @@ yy118:
        goto yy13;
 yy119:
        ++YYCURSOR;
-#line 130 "../src/ast/lex.re"
+#line 131 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr);
         lex_tags(out, true);
@@ -646,7 +646,7 @@ yy119:
 #line 647 "src/ast/lex.cc"
 yy121:
        ++YYCURSOR;
-#line 78 "../src/ast/lex.re"
+#line 79 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr);
         return Rules;
@@ -654,7 +654,7 @@ yy121:
 #line 655 "src/ast/lex.cc"
 yy123:
        ++YYCURSOR;
-#line 124 "../src/ast/lex.re"
+#line 125 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr);
         lex_tags(out, false);
@@ -663,7 +663,7 @@ yy123:
 #line 664 "src/ast/lex.cc"
 yy125:
        ++YYCURSOR;
-#line 115 "../src/ast/lex.re"
+#line 116 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr);
         out.wdelay_line_info_output();
@@ -679,7 +679,7 @@ yy127:
        goto yy13;
 yy128:
        ++YYCURSOR;
-#line 88 "../src/ast/lex.re"
+#line 89 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr);
         lex_end_of_comment(out);
@@ -700,7 +700,7 @@ yy132:
        goto yy13;
 yy133:
        ++YYCURSOR;
-#line 108 "../src/ast/lex.re"
+#line 109 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr);
         out.wdelay_state_goto(0);
@@ -712,7 +712,7 @@ yy135:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych != 'c') goto yy13;
        ++YYCURSOR;
-#line 101 "../src/ast/lex.re"
+#line 102 "../src/ast/lex.re"
        {
         out.wraw(tok, ptr);
         out.wdelay_yymaxnmatch();
@@ -721,7 +721,7 @@ yy135:
     }
 #line 723 "src/ast/lex.cc"
 }
-#line 155 "../src/ast/lex.re"
+#line 156 "../src/ast/lex.re"
 
 }
 
@@ -745,18 +745,18 @@ void Scanner::lex_end_of_comment(OutputFile &out)
        }
 yy140:
        ++YYCURSOR;
-#line 162 "../src/ast/lex.re"
+#line 163 "../src/ast/lex.re"
        { fatal_lc(get_cline(), get_column(), "expected end of block"); }
 #line 751 "src/ast/lex.cc"
 yy142:
        ++YYCURSOR;
 yy143:
-#line 164 "../src/ast/lex.re"
+#line 165 "../src/ast/lex.re"
        { continue; }
 #line 757 "src/ast/lex.cc"
 yy144:
        ++YYCURSOR;
-#line 165 "../src/ast/lex.re"
+#line 166 "../src/ast/lex.re"
        { ++ignored; continue; }
 #line 762 "src/ast/lex.cc"
 yy146:
@@ -767,7 +767,7 @@ yy147:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych != '/') goto yy143;
        ++YYCURSOR;
-#line 166 "../src/ast/lex.re"
+#line 167 "../src/ast/lex.re"
        {
             if (ignored > 0) {
                 cline += ignored;
@@ -778,7 +778,7 @@ yy147:
         }
 #line 780 "src/ast/lex.cc"
 }
-#line 174 "../src/ast/lex.re"
+#line 175 "../src/ast/lex.re"
 }
 }
 
@@ -844,7 +844,7 @@ void Scanner::lex_tags(OutputFile &out, bool mtags)
        }
        ++YYCURSOR;
 yy153:
-#line 181 "../src/ast/lex.re"
+#line 182 "../src/ast/lex.re"
        { fatal_lc(get_cline(), get_column(), "unrecognized configuration"); }
 #line 850 "src/ast/lex.cc"
 yy154:
@@ -854,12 +854,12 @@ yy154:
        if (yybm[0+yych] & 128) {
                goto yy154;
        }
-#line 186 "../src/ast/lex.re"
+#line 187 "../src/ast/lex.re"
        { continue; }
 #line 860 "src/ast/lex.cc"
 yy157:
        ++YYCURSOR;
-#line 187 "../src/ast/lex.re"
+#line 188 "../src/ast/lex.re"
        { ++cline; continue; }
 #line 865 "src/ast/lex.cc"
 yy159:
@@ -880,7 +880,7 @@ yy162:
        goto yy153;
 yy163:
        ++YYCURSOR;
-#line 188 "../src/ast/lex.re"
+#line 189 "../src/ast/lex.re"
        {
             out.wdelay_tags(new ConfTags(fmt, sep), mtags);
             tok = pos = cur;
@@ -923,7 +923,7 @@ yy173:
        goto yy166;
 yy174:
        ++YYCURSOR;
-#line 183 "../src/ast/lex.re"
+#line 184 "../src/ast/lex.re"
        { fmt = lex_conf_string(); continue; }
 #line 929 "src/ast/lex.cc"
 yy176:
@@ -934,11 +934,11 @@ yy176:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych != 'r') goto yy166;
        ++YYCURSOR;
-#line 184 "../src/ast/lex.re"
+#line 185 "../src/ast/lex.re"
        { sep = lex_conf_string(); continue; }
 #line 940 "src/ast/lex.cc"
 }
-#line 193 "../src/ast/lex.re"
+#line 194 "../src/ast/lex.re"
 }
 }
 
@@ -1061,7 +1061,7 @@ yy185:
        if (yybm[0+yych] & 16) {
                goto yy185;
        }
-#line 306 "../src/ast/lex.re"
+#line 307 "../src/ast/lex.re"
        { goto scan; }
 #line 1067 "src/ast/lex.cc"
 yy188:
@@ -1074,9 +1074,8 @@ yy188:
                if (yych == '#') goto yy214;
        }
 yy189:
-#line 313 "../src/ast/lex.re"
+#line 314 "../src/ast/lex.re"
        {
-        if (cur == eof) return 0;
         pos = cur;
         cline++;
         if (lexer_state == LEX_FLEX_NAME) {
@@ -1087,7 +1086,7 @@ yy189:
             goto scan;
         }
     }
-#line 1091 "src/ast/lex.cc"
+#line 1090 "src/ast/lex.cc"
 yy190:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == '\n') goto yy188;
@@ -1095,14 +1094,14 @@ yy190:
 yy191:
        ++YYCURSOR;
 yy192:
-#line 222 "../src/ast/lex.re"
+#line 223 "../src/ast/lex.re"
        { return *tok; }
-#line 1101 "src/ast/lex.cc"
+#line 1100 "src/ast/lex.cc"
 yy193:
        ++YYCURSOR;
-#line 212 "../src/ast/lex.re"
+#line 213 "../src/ast/lex.re"
        { yylval.regexp = lex_str('"'); return TOKEN_REGEXP; }
-#line 1106 "src/ast/lex.cc"
+#line 1105 "src/ast/lex.cc"
 yy195:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '^') {
@@ -1120,21 +1119,21 @@ yy196:
        goto yy184;
 yy197:
        ++YYCURSOR;
-#line 211 "../src/ast/lex.re"
+#line 212 "../src/ast/lex.re"
        { yylval.regexp = lex_str('\''); return TOKEN_REGEXP; }
-#line 1126 "src/ast/lex.cc"
+#line 1125 "src/ast/lex.cc"
 yy199:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == '/') goto yy219;
        goto yy192;
 yy200:
        ++YYCURSOR;
-#line 301 "../src/ast/lex.re"
+#line 302 "../src/ast/lex.re"
        {
         yylval.regexp = ast_dot(cline, get_column());
         return TOKEN_REGEXP;
     }
-#line 1138 "src/ast/lex.cc"
+#line 1137 "src/ast/lex.cc"
 yy202:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == '*') goto yy221;
@@ -1177,9 +1176,9 @@ yy205:
 yy206:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == '^') goto yy233;
-#line 213 "../src/ast/lex.re"
+#line 214 "../src/ast/lex.re"
        { yylval.regexp = lex_cls(false); return TOKEN_REGEXP; }
-#line 1183 "src/ast/lex.cc"
+#line 1182 "src/ast/lex.cc"
 yy208:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == 'e') goto yy235;
@@ -1202,9 +1201,9 @@ yy209:
                }
        }
 yy210:
-#line 202 "../src/ast/lex.re"
-       { lex_code(1); return TOKEN_CODE; }
-#line 1208 "src/ast/lex.cc"
+#line 203 "../src/ast/lex.re"
+       { lex_code_multiline(); return TOKEN_CODE; }
+#line 1207 "src/ast/lex.cc"
 yy211:
        ++YYCURSOR;
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
@@ -1255,38 +1254,38 @@ yy216:
                }
        }
 yy218:
-#line 216 "../src/ast/lex.re"
+#line 217 "../src/ast/lex.re"
        {
         const std::string *name = new std::string(tok + 1, tok_len() - 1);
         yylval.regexp = ast_tag(cline, get_column(), name, tok[0] == '#');
         return TOKEN_REGEXP;
     }
-#line 1265 "src/ast/lex.cc"
+#line 1264 "src/ast/lex.cc"
 yy219:
        ++YYCURSOR;
-#line 209 "../src/ast/lex.re"
+#line 210 "../src/ast/lex.re"
        { tok = cur; return 0; }
-#line 1270 "src/ast/lex.cc"
+#line 1269 "src/ast/lex.cc"
 yy221:
        ++YYCURSOR;
-#line 207 "../src/ast/lex.re"
+#line 208 "../src/ast/lex.re"
        { lex_c_comment(); goto scan; }
-#line 1275 "src/ast/lex.cc"
+#line 1274 "src/ast/lex.cc"
 yy223:
        ++YYCURSOR;
-#line 206 "../src/ast/lex.re"
+#line 207 "../src/ast/lex.re"
        { lex_cpp_comment(); goto scan; }
-#line 1280 "src/ast/lex.cc"
+#line 1279 "src/ast/lex.cc"
 yy225:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == '>') goto yy243;
-#line 203 "../src/ast/lex.re"
-       { tok += 2; lex_code(0); return TOKEN_CODE; }
-#line 1286 "src/ast/lex.cc"
+#line 204 "../src/ast/lex.re"
+       { tok += 2; lex_code_oneline(); return TOKEN_CODE; }
+#line 1285 "src/ast/lex.cc"
 yy227:
        ++YYCURSOR;
        YYCURSOR -= 1;
-#line 283 "../src/ast/lex.re"
+#line 284 "../src/ast/lex.re"
        {
         if (!globopts->FFlag) {
             yylval.str = new std::string (tok, tok_len());
@@ -1304,7 +1303,7 @@ yy227:
             return TOKEN_REGEXP;
         }
     }
-#line 1308 "src/ast/lex.cc"
+#line 1307 "src/ast/lex.cc"
 yy229:
        ++YYCURSOR;
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
@@ -1324,17 +1323,17 @@ yy229:
 yy231:
        ++YYCURSOR;
        YYCURSOR = YYCTXMARKER;
-#line 278 "../src/ast/lex.re"
+#line 279 "../src/ast/lex.re"
        {
         yylval.str = new std::string (tok, tok_len ());
         return TOKEN_ID;
     }
-#line 1333 "src/ast/lex.cc"
+#line 1332 "src/ast/lex.cc"
 yy233:
        ++YYCURSOR;
-#line 214 "../src/ast/lex.re"
+#line 215 "../src/ast/lex.re"
        { yylval.regexp = lex_cls(true);  return TOKEN_REGEXP; }
-#line 1338 "src/ast/lex.cc"
+#line 1337 "src/ast/lex.cc"
 yy235:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == '2') goto yy247;
@@ -1342,12 +1341,12 @@ yy235:
 yy236:
        ++YYCURSOR;
 yy237:
-#line 251 "../src/ast/lex.re"
+#line 252 "../src/ast/lex.re"
        {
         fatal_lc(get_cline(), get_column(),
             "illegal closure form, use '{n}', '{n,}', '{n,m}' where n and m are numbers");
     }
-#line 1351 "src/ast/lex.cc"
+#line 1350 "src/ast/lex.cc"
 yy238:
        ++YYCURSOR;
        if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
@@ -1387,13 +1386,13 @@ yy242:
 yy243:
        ++YYCURSOR;
        YYCURSOR -= 2;
-#line 204 "../src/ast/lex.re"
+#line 205 "../src/ast/lex.re"
        { return *tok; }
-#line 1393 "src/ast/lex.cc"
+#line 1392 "src/ast/lex.cc"
 yy245:
        ++YYCURSOR;
        YYCURSOR = YYCTXMARKER;
-#line 267 "../src/ast/lex.re"
+#line 268 "../src/ast/lex.re"
        {
         yylval.str = new std::string (tok, tok_len ());
         if (globopts->FFlag) {
@@ -1404,7 +1403,7 @@ yy245:
             return TOKEN_ID;
         }
     }
-#line 1408 "src/ast/lex.cc"
+#line 1407 "src/ast/lex.cc"
 yy247:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == 'c') goto yy254;
@@ -1418,7 +1417,7 @@ yy248:
        goto yy237;
 yy249:
        ++YYCURSOR;
-#line 224 "../src/ast/lex.re"
+#line 225 "../src/ast/lex.re"
        {
         if (!s_to_u32_unsafe (tok + 1, cur - 1, yylval.bounds.min)) {
             fatal_lc(get_cline(), get_column(), "repetition count overflow");
@@ -1426,10 +1425,10 @@ yy249:
         yylval.bounds.max = yylval.bounds.min;
         return TOKEN_CLOSESIZE;
     }
-#line 1430 "src/ast/lex.cc"
+#line 1429 "src/ast/lex.cc"
 yy251:
        ++YYCURSOR;
-#line 256 "../src/ast/lex.re"
+#line 257 "../src/ast/lex.re"
        {
         if (!globopts->FFlag) {
             fatal_lc(get_cline(), get_column(),
@@ -1438,7 +1437,7 @@ yy251:
         yylval.str = new std::string (tok + 1, tok_len () - 2); // -2 to omit braces
         return TOKEN_ID;
     }
-#line 1442 "src/ast/lex.cc"
+#line 1441 "src/ast/lex.cc"
 yy253:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == 'n') goto yy259;
@@ -1457,7 +1456,7 @@ yy255:
        goto yy213;
 yy257:
        ++YYCURSOR;
-#line 243 "../src/ast/lex.re"
+#line 244 "../src/ast/lex.re"
        {
         if (!s_to_u32_unsafe (tok + 1, cur - 2, yylval.bounds.min)) {
             fatal_lc(get_cline(), get_column(), "repetition lower bound overflow");
@@ -1465,19 +1464,19 @@ yy257:
         yylval.bounds.max = std::numeric_limits<uint32_t>::max();
         return TOKEN_CLOSESIZE;
     }
-#line 1469 "src/ast/lex.cc"
+#line 1468 "src/ast/lex.cc"
 yy259:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == 'e') goto yy264;
        goto yy213;
 yy260:
        ++YYCURSOR;
-#line 265 "../src/ast/lex.re"
+#line 266 "../src/ast/lex.re"
        { return TOKEN_CONF; }
-#line 1478 "src/ast/lex.cc"
+#line 1477 "src/ast/lex.cc"
 yy262:
        ++YYCURSOR;
-#line 232 "../src/ast/lex.re"
+#line 233 "../src/ast/lex.re"
        {
         const char * p = strchr (tok, ',');
         if (!s_to_u32_unsafe (tok + 1, p, yylval.bounds.min)) {
@@ -1488,7 +1487,7 @@ yy262:
         }
         return TOKEN_CLOSESIZE;
     }
-#line 1492 "src/ast/lex.cc"
+#line 1491 "src/ast/lex.cc"
 yy264:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '0') goto yy266;
@@ -1544,12 +1543,12 @@ yy269:
 yy271:
        ++YYCURSOR;
        YYCURSOR = YYCTXMARKER;
-#line 308 "../src/ast/lex.re"
+#line 309 "../src/ast/lex.re"
        {
         set_sourceline ();
         return TOKEN_LINE_INFO;
     }
-#line 1553 "src/ast/lex.cc"
+#line 1552 "src/ast/lex.cc"
 yy273:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych == '\n') goto yy271;
@@ -1579,15 +1578,115 @@ yy277:
 
 }
 
-void Scanner::lex_code(uint32_t depth)
+void Scanner::lex_code_oneline()
 {
     const uint32_t line = cline;
 code:
 
-#line 1588 "src/ast/lex.cc"
+#line 1587 "src/ast/lex.cc"
+{
+       YYCTYPE yych;
+       if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+       yych = (YYCTYPE)*YYCURSOR;
+       if (yych <= '&') {
+               if (yych <= '\f') {
+                       if (yych <= 0x00) goto yy280;
+                       if (yych == '\n') goto yy284;
+                       goto yy282;
+               } else {
+                       if (yych <= '\r') goto yy286;
+                       if (yych == '"') goto yy287;
+                       goto yy282;
+               }
+       } else {
+               if (yych <= 'z') {
+                       if (yych <= '\'') goto yy287;
+                       if (yych == '/') goto yy289;
+                       goto yy282;
+               } else {
+                       if (yych == '|') goto yy282;
+                       if (yych <= '}') goto yy290;
+                       goto yy282;
+               }
+       }
+yy280:
+       ++YYCURSOR;
+#line 346 "../src/ast/lex.re"
+       { fail_if_eof(); goto code; }
+#line 1617 "src/ast/lex.cc"
+yy282:
+       ++YYCURSOR;
+yy283:
+#line 351 "../src/ast/lex.re"
+       { goto code; }
+#line 1623 "src/ast/lex.cc"
+yy284:
+       yych = (YYCTYPE)*++YYCURSOR;
+       if (yych <= '\f') {
+               if (yych <= 0x08) goto yy285;
+               if (yych <= '\n') goto yy292;
+       } else {
+               if (yych <= '\r') goto yy292;
+               if (yych == ' ') goto yy292;
+       }
+yy285:
+#line 339 "../src/ast/lex.re"
+       {
+        tok += strspn(tok, " \t\r\n");
+        while (cur > tok && strchr(" \t\r\n", cur[-1])) --cur;
+        yylval.code = new Code(get_fname (), line, tok, tok_len ());
+        return;
+    }
+#line 1641 "src/ast/lex.cc"
+yy286:
+       yych = (YYCTYPE)*++YYCURSOR;
+       if (yych == '\n') goto yy284;
+       goto yy283;
+yy287:
+       ++YYCURSOR;
+#line 350 "../src/ast/lex.re"
+       { lex_string(cur[-1]); goto code; }
+#line 1650 "src/ast/lex.cc"
+yy289:
+       yych = (YYCTYPE)*++YYCURSOR;
+       if (yych == '*') goto yy294;
+       if (yych == '/') goto yy296;
+       goto yy283;
+yy290:
+       ++YYCURSOR;
+#line 347 "../src/ast/lex.re"
+       { fatal_l(get_cline(), "Curly braces are not allowed after ':='"); }
+#line 1660 "src/ast/lex.cc"
+yy292:
+       ++YYCURSOR;
+       YYCURSOR -= 1;
+#line 338 "../src/ast/lex.re"
+       { goto code; }
+#line 1666 "src/ast/lex.cc"
+yy294:
+       ++YYCURSOR;
+#line 348 "../src/ast/lex.re"
+       { lex_c_comment(); goto code; }
+#line 1671 "src/ast/lex.cc"
+yy296:
+       ++YYCURSOR;
+#line 349 "../src/ast/lex.re"
+       { lex_cpp_comment(); goto code; }
+#line 1676 "src/ast/lex.cc"
+}
+#line 352 "../src/ast/lex.re"
+
+}
+
+void Scanner::lex_code_multiline()
+{
+    const uint32_t line = cline;
+    uint32_t depth = 1;
+code:
+
+#line 1688 "src/ast/lex.cc"
 {
        YYCTYPE yych;
-       unsigned int yyaccept = 0;
        static const unsigned char yybm[] = {
                  0, 128, 128, 128, 128, 128, 128, 128, 
                128, 160,   0, 128, 128, 128, 128, 128, 
@@ -1622,268 +1721,198 @@ code:
                128, 128, 128, 128, 128, 128, 128, 128, 
                128, 128, 128, 128, 128, 128, 128, 128, 
        };
-       if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
+       if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
        yych = (YYCTYPE)*YYCURSOR;
        if (yych <= '&') {
                if (yych <= '\f') {
-                       if (yych <= 0x00) goto yy280;
-                       if (yych == '\n') goto yy284;
-                       goto yy282;
+                       if (yych <= 0x00) goto yy300;
+                       if (yych == '\n') goto yy304;
+                       goto yy302;
                } else {
-                       if (yych <= '\r') goto yy286;
-                       if (yych == '"') goto yy287;
-                       goto yy282;
+                       if (yych <= '\r') goto yy306;
+                       if (yych == '"') goto yy307;
+                       goto yy302;
                }
        } else {
                if (yych <= 'z') {
-                       if (yych <= '\'') goto yy287;
-                       if (yych == '/') goto yy289;
-                       goto yy282;
+                       if (yych <= '\'') goto yy307;
+                       if (yych == '/') goto yy309;
+                       goto yy302;
                } else {
-                       if (yych <= '{') goto yy290;
-                       if (yych == '}') goto yy292;
-                       goto yy282;
+                       if (yych <= '{') goto yy310;
+                       if (yych == '}') goto yy312;
+                       goto yy302;
                }
        }
-yy280:
+yy300:
        ++YYCURSOR;
-#line 387 "../src/ast/lex.re"
-       {
-        if (cur == eof) {
-            if (depth) fatal_l(get_cline(), "missing '}'");
-        }
-        goto code;
-    }
-#line 1658 "src/ast/lex.cc"
-yy282:
+#line 372 "../src/ast/lex.re"
+       { fail_if_eof(); goto code; }
+#line 1752 "src/ast/lex.cc"
+yy302:
        ++YYCURSOR;
-yy283:
-#line 397 "../src/ast/lex.re"
+yy303:
+#line 376 "../src/ast/lex.re"
        { goto code; }
-#line 1664 "src/ast/lex.cc"
-yy284:
-       yyaccept = 0;
+#line 1758 "src/ast/lex.cc"
+yy304:
        yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
-       if (yych <= '\r') {
-               if (yych <= '\t') {
-                       if (yych >= '\t') goto yy294;
-               } else {
-                       if (yych <= '\n') goto yy296;
-                       if (yych >= '\r') goto yy296;
-               }
-       } else {
-               if (yych <= ' ') {
-                       if (yych >= ' ') goto yy294;
-               } else {
-                       if (yych == '#') goto yy297;
-               }
+       if (yybm[0+yych] & 32) {
+               goto yy314;
        }
-yy285:
-#line 372 "../src/ast/lex.re"
-       {
-        if (depth == 0) {
-            tok += strspn(tok, " \t\r\n");
-            while (cur > tok && strchr(" \t\r\n", cur[-1])) --cur;
-            yylval.code = new Code(get_fname (), line, tok, tok_len ());
-            return;
-        }
-        else if (cur == eof) {
-            fatal_l(get_cline(), "missing '}'");
-        }
-        pos = cur;
-        cline++;
-        goto code;
-    }
-#line 1698 "src/ast/lex.cc"
-yy286:
+       if (yych == '#') goto yy317;
+yy305:
+#line 371 "../src/ast/lex.re"
+       { pos = cur; cline++; goto code; }
+#line 1768 "src/ast/lex.cc"
+yy306:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy284;
-       goto yy283;
-yy287:
+       if (yych == '\n') goto yy304;
+       goto yy303;
+yy307:
        ++YYCURSOR;
-#line 396 "../src/ast/lex.re"
+#line 375 "../src/ast/lex.re"
        { lex_string(cur[-1]); goto code; }
-#line 1707 "src/ast/lex.cc"
-yy289:
+#line 1777 "src/ast/lex.cc"
+yy309:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '*') goto yy300;
-       if (yych == '/') goto yy302;
-       goto yy283;
-yy290:
+       if (yych == '*') goto yy319;
+       if (yych == '/') goto yy321;
+       goto yy303;
+yy310:
        ++YYCURSOR;
-#line 349 "../src/ast/lex.re"
-       {
-        if (depth == 0) {
-            fatal_l(get_cline(), "Curly braces are not allowed after ':='");
-        }
-        else {
-            ++depth;
-        }
-        goto code;
-    }
-#line 1725 "src/ast/lex.cc"
-yy292:
+#line 369 "../src/ast/lex.re"
+       { ++depth; goto code; }
+#line 1787 "src/ast/lex.cc"
+yy312:
        ++YYCURSOR;
-#line 338 "../src/ast/lex.re"
+#line 361 "../src/ast/lex.re"
        {
-        if (depth == 0) {
-            fatal_l(get_cline(), "Curly braces are not allowed after ':='");
-        }
-        else if (--depth == 0) {
+        if (--depth == 0) {
             yylval.code = new Code(get_fname (), line, tok, tok_len ());
             return;
         }
         goto code;
     }
-#line 1739 "src/ast/lex.cc"
-yy294:
-       yyaccept = 1;
-       yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
-       if (yych <= 0x1F) {
-               if (yych == '\t') goto yy304;
-       } else {
-               if (yych <= ' ') goto yy304;
-               if (yych == '#') goto yy297;
-       }
-yy295:
-       YYCURSOR -= 1;
-#line 364 "../src/ast/lex.re"
-       {
-        if (depth == 0) goto code;
-        else if (cur == eof) fatal_l(get_cline(), "missing '}'");
-        pos = cur;
-        cline++;
-        goto code;
-    }
-#line 1759 "src/ast/lex.cc"
-yy296:
-       ++YYCURSOR;
-       goto yy295;
-yy297:
+#line 1798 "src/ast/lex.cc"
+yy314:
        ++YYCURSOR;
-       if ((YYLIMIT - YYCURSOR) < 5) YYFILL(5);
+       if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = (YYCTYPE)*YYCURSOR;
        if (yybm[0+yych] & 32) {
-               goto yy297;
+               goto yy314;
        }
-       if (yych == 'l') goto yy306;
-yy299:
+       if (yych == '#') goto yy317;
+yy316:
        YYCURSOR = YYMARKER;
-       if (yyaccept == 0) {
-               goto yy285;
+       goto yy305;
+yy317:
+       ++YYCURSOR;
+       if ((YYLIMIT - YYCURSOR) < 5) YYFILL(5);
+       yych = (YYCTYPE)*YYCURSOR;
+       if (yych <= 0x1F) {
+               if (yych == '\t') goto yy317;
+               goto yy316;
        } else {
-               goto yy295;
+               if (yych <= ' ') goto yy317;
+               if (yych == 'l') goto yy323;
+               goto yy316;
        }
-yy300:
+yy319:
        ++YYCURSOR;
-#line 394 "../src/ast/lex.re"
+#line 373 "../src/ast/lex.re"
        { lex_c_comment(); goto code; }
-#line 1782 "src/ast/lex.cc"
-yy302:
+#line 1826 "src/ast/lex.cc"
+yy321:
        ++YYCURSOR;
-#line 395 "../src/ast/lex.re"
+#line 374 "../src/ast/lex.re"
        { lex_cpp_comment(); goto code; }
-#line 1787 "src/ast/lex.cc"
-yy304:
-       ++YYCURSOR;
-       if (YYLIMIT <= YYCURSOR) YYFILL(1);
-       yych = (YYCTYPE)*YYCURSOR;
-       if (yych <= 0x1F) {
-               if (yych == '\t') goto yy304;
-               goto yy299;
-       } else {
-               if (yych <= ' ') goto yy304;
-               if (yych == '#') goto yy297;
-               goto yy299;
-       }
-yy306:
+#line 1831 "src/ast/lex.cc"
+yy323:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych != 'i') goto yy299;
+       if (yych != 'i') goto yy316;
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych != 'n') goto yy299;
+       if (yych != 'n') goto yy316;
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych != 'e') goto yy299;
+       if (yych != 'e') goto yy316;
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych <= '0') goto yy311;
-       if (yych <= '9') goto yy299;
-       goto yy311;
-yy310:
+       if (yych <= '0') goto yy328;
+       if (yych <= '9') goto yy316;
+       goto yy328;
+yy327:
        ++YYCURSOR;
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = (YYCTYPE)*YYCURSOR;
-yy311:
+yy328:
        if (yych <= 0x1F) {
-               if (yych == '\t') goto yy310;
-               goto yy299;
+               if (yych == '\t') goto yy327;
+               goto yy316;
        } else {
-               if (yych <= ' ') goto yy310;
-               if (yych <= '0') goto yy299;
-               if (yych >= ':') goto yy299;
+               if (yych <= ' ') goto yy327;
+               if (yych <= '0') goto yy316;
+               if (yych >= ':') goto yy316;
                YYCTXMARKER = YYCURSOR;
        }
-yy312:
+yy329:
        ++YYCURSOR;
        if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
        yych = (YYCTYPE)*YYCURSOR;
        if (yybm[0+yych] & 64) {
-               goto yy312;
+               goto yy329;
        }
        if (yych <= '\f') {
-               if (yych <= 0x08) goto yy299;
-               if (yych <= '\t') goto yy314;
-               if (yych <= '\n') goto yy316;
-               goto yy299;
+               if (yych <= 0x08) goto yy316;
+               if (yych <= '\t') goto yy331;
+               if (yych <= '\n') goto yy333;
+               goto yy316;
        } else {
-               if (yych <= '\r') goto yy318;
-               if (yych != ' ') goto yy299;
+               if (yych <= '\r') goto yy335;
+               if (yych != ' ') goto yy316;
        }
-yy314:
+yy331:
        ++YYCURSOR;
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = (YYCTYPE)*YYCURSOR;
        if (yych <= 0x1F) {
-               if (yych == '\t') goto yy314;
-               goto yy299;
+               if (yych == '\t') goto yy331;
+               goto yy316;
        } else {
-               if (yych <= ' ') goto yy314;
-               if (yych == '"') goto yy319;
-               goto yy299;
+               if (yych <= ' ') goto yy331;
+               if (yych == '"') goto yy336;
+               goto yy316;
        }
-yy316:
+yy333:
        ++YYCURSOR;
        YYCURSOR = YYCTXMARKER;
-#line 359 "../src/ast/lex.re"
-       {
-        set_sourceline ();
-        goto code;
-    }
-#line 1861 "src/ast/lex.cc"
-yy318:
+#line 370 "../src/ast/lex.re"
+       { set_sourceline (); goto code; }
+#line 1890 "src/ast/lex.cc"
+yy335:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy316;
-       goto yy299;
-yy319:
+       if (yych == '\n') goto yy333;
+       goto yy316;
+yy336:
        ++YYCURSOR;
        if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
        yych = (YYCTYPE)*YYCURSOR;
        if (yybm[0+yych] & 128) {
-               goto yy319;
+               goto yy336;
        }
-       if (yych <= '\n') goto yy299;
-       if (yych >= '#') goto yy322;
+       if (yych <= '\n') goto yy316;
+       if (yych >= '#') goto yy339;
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy316;
-       if (yych == '\r') goto yy318;
-       goto yy299;
-yy322:
+       if (yych == '\n') goto yy333;
+       if (yych == '\r') goto yy335;
+       goto yy316;
+yy339:
        ++YYCURSOR;
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = (YYCTYPE)*YYCURSOR;
-       if (yych <= 0x00) goto yy299;
-       if (yych == '\n') goto yy299;
-       goto yy319;
+       if (yych <= 0x00) goto yy316;
+       if (yych == '\n') goto yy316;
+       goto yy336;
 }
-#line 398 "../src/ast/lex.re"
+#line 377 "../src/ast/lex.re"
 
 }
 
@@ -1891,70 +1920,70 @@ void Scanner::lex_string(char delim)
 {
 loop:
 
-#line 1895 "src/ast/lex.cc"
+#line 1924 "src/ast/lex.cc"
 {
        YYCTYPE yych;
        if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
        yych = (YYCTYPE)*YYCURSOR;
        if (yych <= '!') {
                if (yych <= '\n') {
-                       if (yych <= 0x00) goto yy325;
-                       if (yych <= '\t') goto yy327;
-                       goto yy329;
+                       if (yych <= 0x00) goto yy342;
+                       if (yych <= '\t') goto yy344;
+                       goto yy346;
                } else {
-                       if (yych == '\r') goto yy331;
-                       goto yy327;
+                       if (yych == '\r') goto yy348;
+                       goto yy344;
                }
        } else {
                if (yych <= '\'') {
-                       if (yych <= '"') goto yy332;
-                       if (yych <= '&') goto yy327;
-                       goto yy332;
+                       if (yych <= '"') goto yy349;
+                       if (yych <= '&') goto yy344;
+                       goto yy349;
                } else {
-                       if (yych == '\\') goto yy334;
-                       goto yy327;
+                       if (yych == '\\') goto yy351;
+                       goto yy344;
                }
        }
-yy325:
+yy342:
        ++YYCURSOR;
-#line 408 "../src/ast/lex.re"
-       { if (cur == eof) fatal_l(get_cline(), "unexpected end of input"); else goto loop; }
-#line 1923 "src/ast/lex.cc"
-yy327:
+#line 387 "../src/ast/lex.re"
+       { fail_if_eof(); goto loop; }
+#line 1952 "src/ast/lex.cc"
+yy344:
        ++YYCURSOR;
-yy328:
-#line 409 "../src/ast/lex.re"
+yy345:
+#line 388 "../src/ast/lex.re"
        { goto loop; }
-#line 1929 "src/ast/lex.cc"
-yy329:
+#line 1958 "src/ast/lex.cc"
+yy346:
        ++YYCURSOR;
-#line 407 "../src/ast/lex.re"
+#line 386 "../src/ast/lex.re"
        { pos = cur; ++cline; goto loop; }
-#line 1934 "src/ast/lex.cc"
-yy331:
+#line 1963 "src/ast/lex.cc"
+yy348:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy329;
-       goto yy328;
-yy332:
+       if (yych == '\n') goto yy346;
+       goto yy345;
+yy349:
        ++YYCURSOR;
-#line 405 "../src/ast/lex.re"
+#line 384 "../src/ast/lex.re"
        { if (cur[-1] == delim) return; else goto loop; }
-#line 1943 "src/ast/lex.cc"
-yy334:
+#line 1972 "src/ast/lex.cc"
+yy351:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '&') {
-               if (yych != '"') goto yy328;
+               if (yych != '"') goto yy345;
        } else {
-               if (yych <= '\'') goto yy335;
-               if (yych != '\\') goto yy328;
+               if (yych <= '\'') goto yy352;
+               if (yych != '\\') goto yy345;
        }
-yy335:
+yy352:
        ++YYCURSOR;
-#line 406 "../src/ast/lex.re"
+#line 385 "../src/ast/lex.re"
        { goto loop; }
-#line 1956 "src/ast/lex.cc"
+#line 1985 "src/ast/lex.cc"
 }
-#line 410 "../src/ast/lex.re"
+#line 389 "../src/ast/lex.re"
 
 }
 
@@ -1962,49 +1991,49 @@ void Scanner::lex_c_comment()
 {
 loop:
 
-#line 1966 "src/ast/lex.cc"
+#line 1995 "src/ast/lex.cc"
 {
        YYCTYPE yych;
        if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
        yych = (YYCTYPE)*YYCURSOR;
        if (yych <= '\f') {
-               if (yych <= 0x00) goto yy339;
-               if (yych == '\n') goto yy343;
-               goto yy341;
+               if (yych <= 0x00) goto yy356;
+               if (yych == '\n') goto yy360;
+               goto yy358;
        } else {
-               if (yych <= '\r') goto yy345;
-               if (yych == '*') goto yy346;
-               goto yy341;
+               if (yych <= '\r') goto yy362;
+               if (yych == '*') goto yy363;
+               goto yy358;
        }
-yy339:
+yy356:
        ++YYCURSOR;
-#line 419 "../src/ast/lex.re"
-       { if (cur == eof) fatal_l(get_cline(), "end of input in comment"); else goto loop; }
-#line 1984 "src/ast/lex.cc"
-yy341:
+#line 398 "../src/ast/lex.re"
+       { fail_if_eof(); goto loop; }
+#line 2013 "src/ast/lex.cc"
+yy358:
        ++YYCURSOR;
-yy342:
-#line 420 "../src/ast/lex.re"
+yy359:
+#line 399 "../src/ast/lex.re"
        { goto loop; }
-#line 1990 "src/ast/lex.cc"
-yy343:
+#line 2019 "src/ast/lex.cc"
+yy360:
        ++YYCURSOR;
-#line 418 "../src/ast/lex.re"
+#line 397 "../src/ast/lex.re"
        { pos = cur; ++cline; goto loop; }
-#line 1995 "src/ast/lex.cc"
-yy345:
+#line 2024 "src/ast/lex.cc"
+yy362:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy343;
-       goto yy342;
-yy346:
+       if (yych == '\n') goto yy360;
+       goto yy359;
+yy363:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych != '/') goto yy342;
+       if (yych != '/') goto yy359;
        ++YYCURSOR;
-#line 417 "../src/ast/lex.re"
+#line 396 "../src/ast/lex.re"
        { return; }
-#line 2006 "src/ast/lex.cc"
+#line 2035 "src/ast/lex.cc"
 }
-#line 421 "../src/ast/lex.re"
+#line 400 "../src/ast/lex.re"
 
 }
 
@@ -2012,41 +2041,41 @@ void Scanner::lex_cpp_comment()
 {
 loop:
 
-#line 2016 "src/ast/lex.cc"
+#line 2045 "src/ast/lex.cc"
 {
        YYCTYPE yych;
        if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
        yych = (YYCTYPE)*YYCURSOR;
        if (yych <= '\n') {
-               if (yych <= 0x00) goto yy351;
-               if (yych <= '\t') goto yy353;
-               goto yy355;
+               if (yych <= 0x00) goto yy368;
+               if (yych <= '\t') goto yy370;
+               goto yy372;
        } else {
-               if (yych == '\r') goto yy357;
-               goto yy353;
+               if (yych == '\r') goto yy374;
+               goto yy370;
        }
-yy351:
+yy368:
        ++YYCURSOR;
-#line 429 "../src/ast/lex.re"
-       { if (cur == eof) fatal_l(get_cline(), "end of input in comment"); else goto loop; }
-#line 2033 "src/ast/lex.cc"
-yy353:
+#line 408 "../src/ast/lex.re"
+       { fail_if_eof(); goto loop; }
+#line 2062 "src/ast/lex.cc"
+yy370:
        ++YYCURSOR;
-yy354:
-#line 430 "../src/ast/lex.re"
+yy371:
+#line 409 "../src/ast/lex.re"
        { goto loop; }
-#line 2039 "src/ast/lex.cc"
-yy355:
+#line 2068 "src/ast/lex.cc"
+yy372:
        ++YYCURSOR;
-#line 428 "../src/ast/lex.re"
+#line 407 "../src/ast/lex.re"
        { pos = cur; ++cline; return; }
-#line 2044 "src/ast/lex.cc"
-yy357:
+#line 2073 "src/ast/lex.cc"
+yy374:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy355;
-       goto yy354;
+       if (yych == '\n') goto yy372;
+       goto yy371;
 }
-#line 431 "../src/ast/lex.re"
+#line 410 "../src/ast/lex.re"
 
 }
 
@@ -2058,44 +2087,44 @@ fst:
     tok = cur;
     c = get_column();
     
-#line 2062 "src/ast/lex.cc"
+#line 2091 "src/ast/lex.cc"
 {
        YYCTYPE yych;
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = (YYCTYPE)*YYCURSOR;
-       if (yych == ']') goto yy361;
-#line 443 "../src/ast/lex.re"
+       if (yych == ']') goto yy378;
+#line 422 "../src/ast/lex.re"
        { l = lex_cls_chr(); goto snd; }
-#line 2070 "src/ast/lex.cc"
-yy361:
+#line 2099 "src/ast/lex.cc"
+yy378:
        ++YYCURSOR;
-#line 442 "../src/ast/lex.re"
+#line 421 "../src/ast/lex.re"
        { return ast_cls(cline, c0, cls, neg); }
-#line 2075 "src/ast/lex.cc"
+#line 2104 "src/ast/lex.cc"
 }
-#line 444 "../src/ast/lex.re"
+#line 423 "../src/ast/lex.re"
 
 snd:
     
-#line 2081 "src/ast/lex.cc"
+#line 2110 "src/ast/lex.cc"
 {
        YYCTYPE yych;
        if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
        yych = (YYCTYPE)*(YYMARKER = YYCURSOR);
-       if (yych == '-') goto yy366;
-yy365:
-#line 447 "../src/ast/lex.re"
+       if (yych == '-') goto yy383;
+yy382:
+#line 426 "../src/ast/lex.re"
        { u = l; goto add; }
-#line 2090 "src/ast/lex.cc"
-yy366:
+#line 2119 "src/ast/lex.cc"
+yy383:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych != ']') goto yy368;
+       if (yych != ']') goto yy385;
        YYCURSOR = YYMARKER;
-       goto yy365;
-yy368:
+       goto yy382;
+yy385:
        ++YYCURSOR;
        YYCURSOR -= 1;
-#line 448 "../src/ast/lex.re"
+#line 427 "../src/ast/lex.re"
        {
             u = lex_cls_chr();
             if (l > u) {
@@ -2104,9 +2133,9 @@ yy368:
             }
             goto add;
         }
-#line 2108 "src/ast/lex.cc"
+#line 2137 "src/ast/lex.cc"
 }
-#line 456 "../src/ast/lex.re"
+#line 435 "../src/ast/lex.re"
 
 add:
     cls->push_back(ASTRange(l, u, c));
@@ -2118,297 +2147,306 @@ uint32_t Scanner::lex_cls_chr()
     tok = cur;
     const uint32_t l = get_cline(), c = get_column();
     
-#line 2122 "src/ast/lex.cc"
+#line 2151 "src/ast/lex.cc"
 {
        YYCTYPE yych;
        unsigned int yyaccept = 0;
        if ((YYLIMIT - YYCURSOR) < 10) YYFILL(10);
        yych = (YYCTYPE)*YYCURSOR;
        if (yych <= '\f') {
-               if (yych == '\n') goto yy374;
+               if (yych <= 0x00) goto yy389;
+               if (yych == '\n') goto yy393;
+               goto yy391;
        } else {
-               if (yych <= '\r') goto yy376;
-               if (yych == '\\') goto yy377;
+               if (yych <= '\r') goto yy395;
+               if (yych == '\\') goto yy396;
+               goto yy391;
        }
+yy389:
        ++YYCURSOR;
-yy373:
-#line 473 "../src/ast/lex.re"
+#line 447 "../src/ast/lex.re"
+       { fail_if_eof(); return 0; }
+#line 2170 "src/ast/lex.cc"
+yy391:
+       ++YYCURSOR;
+yy392:
+#line 453 "../src/ast/lex.re"
        { return static_cast<uint8_t>(tok[0]); }
-#line 2138 "src/ast/lex.cc"
-yy374:
+#line 2176 "src/ast/lex.cc"
+yy393:
        ++YYCURSOR;
-#line 468 "../src/ast/lex.re"
+#line 448 "../src/ast/lex.re"
        { fatal_lc(l, c, "newline in character class"); }
-#line 2143 "src/ast/lex.cc"
-yy376:
+#line 2181 "src/ast/lex.cc"
+yy395:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy374;
-       goto yy373;
-yy377:
+       if (yych == '\n') goto yy393;
+       goto yy392;
+yy396:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= ']') {
                if (yych <= '3') {
                        if (yych <= '\r') {
-                               if (yych == '\n') goto yy374;
-                               if (yych >= '\r') goto yy380;
+                               if (yych == '\n') goto yy393;
+                               if (yych >= '\r') goto yy399;
                        } else {
-                               if (yych == '-') goto yy381;
-                               if (yych >= '0') goto yy383;
+                               if (yych == '-') goto yy400;
+                               if (yych >= '0') goto yy402;
                        }
                } else {
                        if (yych <= 'W') {
-                               if (yych <= '7') goto yy385;
-                               if (yych == 'U') goto yy386;
+                               if (yych <= '7') goto yy404;
+                               if (yych == 'U') goto yy405;
                        } else {
-                               if (yych <= 'X') goto yy388;
-                               if (yych <= '[') goto yy378;
-                               if (yych <= '\\') goto yy389;
-                               goto yy391;
+                               if (yych <= 'X') goto yy407;
+                               if (yych <= '[') goto yy397;
+                               if (yych <= '\\') goto yy408;
+                               goto yy410;
                        }
                }
        } else {
                if (yych <= 'q') {
                        if (yych <= 'e') {
-                               if (yych <= '`') goto yy378;
-                               if (yych <= 'a') goto yy393;
-                               if (yych <= 'b') goto yy395;
+                               if (yych <= '`') goto yy397;
+                               if (yych <= 'a') goto yy412;
+                               if (yych <= 'b') goto yy414;
                        } else {
-                               if (yych <= 'f') goto yy397;
-                               if (yych == 'n') goto yy399;
+                               if (yych <= 'f') goto yy416;
+                               if (yych == 'n') goto yy418;
                        }
                } else {
                        if (yych <= 'u') {
-                               if (yych <= 'r') goto yy401;
-                               if (yych <= 's') goto yy378;
-                               if (yych <= 't') goto yy403;
-                               goto yy388;
+                               if (yych <= 'r') goto yy420;
+                               if (yych <= 's') goto yy397;
+                               if (yych <= 't') goto yy422;
+                               goto yy407;
                        } else {
-                               if (yych <= 'v') goto yy405;
-                               if (yych == 'x') goto yy407;
+                               if (yych <= 'v') goto yy424;
+                               if (yych == 'x') goto yy426;
                        }
                }
        }
-yy378:
+yy397:
        ++YYCURSOR;
-yy379:
-#line 486 "../src/ast/lex.re"
+yy398:
+#line 466 "../src/ast/lex.re"
        {
             warn.useless_escape(cline, get_column(), tok[1]);
             return static_cast<uint8_t>(tok[1]);
         }
-#line 2200 "src/ast/lex.cc"
-yy380:
+#line 2238 "src/ast/lex.cc"
+yy399:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy374;
-       goto yy379;
-yy381:
+       if (yych == '\n') goto yy393;
+       goto yy398;
+yy400:
        ++YYCURSOR;
-#line 484 "../src/ast/lex.re"
+#line 464 "../src/ast/lex.re"
        { return static_cast<uint8_t>('-'); }
-#line 2209 "src/ast/lex.cc"
-yy383:
+#line 2247 "src/ast/lex.cc"
+yy402:
        yyaccept = 0;
        yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
-       if (yych <= '/') goto yy384;
-       if (yych <= '7') goto yy408;
-yy384:
-#line 470 "../src/ast/lex.re"
+       if (yych <= '/') goto yy403;
+       if (yych <= '7') goto yy427;
+yy403:
+#line 450 "../src/ast/lex.re"
        { fatal_lc(l, c, "syntax error in octal escape sequence"); }
-#line 2218 "src/ast/lex.cc"
-yy385:
+#line 2256 "src/ast/lex.cc"
+yy404:
        ++YYCURSOR;
-       goto yy384;
-yy386:
+       goto yy403;
+yy405:
        yyaccept = 1;
        yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
        if (yych <= '@') {
-               if (yych <= '/') goto yy387;
-               if (yych <= '9') goto yy410;
+               if (yych <= '/') goto yy406;
+               if (yych <= '9') goto yy429;
        } else {
-               if (yych <= 'F') goto yy410;
-               if (yych <= '`') goto yy387;
-               if (yych <= 'f') goto yy410;
+               if (yych <= 'F') goto yy429;
+               if (yych <= '`') goto yy406;
+               if (yych <= 'f') goto yy429;
        }
-yy387:
-#line 469 "../src/ast/lex.re"
+yy406:
+#line 449 "../src/ast/lex.re"
        { fatal_lc(l, c, "syntax error in hexadecimal escape sequence"); }
-#line 2236 "src/ast/lex.cc"
-yy388:
+#line 2274 "src/ast/lex.cc"
+yy407:
        yyaccept = 1;
        yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
        if (yych <= '@') {
-               if (yych <= '/') goto yy387;
-               if (yych <= '9') goto yy411;
-               goto yy387;
+               if (yych <= '/') goto yy406;
+               if (yych <= '9') goto yy430;
+               goto yy406;
        } else {
-               if (yych <= 'F') goto yy411;
-               if (yych <= '`') goto yy387;
-               if (yych <= 'f') goto yy411;
-               goto yy387;
+               if (yych <= 'F') goto yy430;
+               if (yych <= '`') goto yy406;
+               if (yych <= 'f') goto yy430;
+               goto yy406;
        }
-yy389:
+yy408:
        ++YYCURSOR;
-#line 483 "../src/ast/lex.re"
+#line 463 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\\'); }
-#line 2254 "src/ast/lex.cc"
-yy391:
+#line 2292 "src/ast/lex.cc"
+yy410:
        ++YYCURSOR;
-#line 485 "../src/ast/lex.re"
+#line 465 "../src/ast/lex.re"
        { return static_cast<uint8_t>(']'); }
-#line 2259 "src/ast/lex.cc"
-yy393:
+#line 2297 "src/ast/lex.cc"
+yy412:
        ++YYCURSOR;
-#line 476 "../src/ast/lex.re"
+#line 456 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\a'); }
-#line 2264 "src/ast/lex.cc"
-yy395:
+#line 2302 "src/ast/lex.cc"
+yy414:
        ++YYCURSOR;
-#line 477 "../src/ast/lex.re"
+#line 457 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\b'); }
-#line 2269 "src/ast/lex.cc"
-yy397:
+#line 2307 "src/ast/lex.cc"
+yy416:
        ++YYCURSOR;
-#line 478 "../src/ast/lex.re"
+#line 458 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\f'); }
-#line 2274 "src/ast/lex.cc"
-yy399:
+#line 2312 "src/ast/lex.cc"
+yy418:
        ++YYCURSOR;
-#line 479 "../src/ast/lex.re"
+#line 459 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\n'); }
-#line 2279 "src/ast/lex.cc"
-yy401:
+#line 2317 "src/ast/lex.cc"
+yy420:
        ++YYCURSOR;
-#line 480 "../src/ast/lex.re"
+#line 460 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\r'); }
-#line 2284 "src/ast/lex.cc"
-yy403:
+#line 2322 "src/ast/lex.cc"
+yy422:
        ++YYCURSOR;
-#line 481 "../src/ast/lex.re"
+#line 461 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\t'); }
-#line 2289 "src/ast/lex.cc"
-yy405:
+#line 2327 "src/ast/lex.cc"
+yy424:
        ++YYCURSOR;
-#line 482 "../src/ast/lex.re"
+#line 462 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\v'); }
-#line 2294 "src/ast/lex.cc"
-yy407:
+#line 2332 "src/ast/lex.cc"
+yy426:
        yyaccept = 1;
        yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
        if (yych <= '@') {
-               if (yych <= '/') goto yy387;
-               if (yych <= '9') goto yy412;
-               goto yy387;
+               if (yych <= '/') goto yy406;
+               if (yych <= '9') goto yy431;
+               goto yy406;
        } else {
-               if (yych <= 'F') goto yy412;
-               if (yych <= '`') goto yy387;
-               if (yych <= 'f') goto yy412;
-               goto yy387;
+               if (yych <= 'F') goto yy431;
+               if (yych <= '`') goto yy406;
+               if (yych <= 'f') goto yy431;
+               goto yy406;
        }
-yy408:
+yy427:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych <= '/') goto yy409;
-       if (yych <= '7') goto yy413;
-yy409:
+       if (yych <= '/') goto yy428;
+       if (yych <= '7') goto yy432;
+yy428:
        YYCURSOR = YYMARKER;
        if (yyaccept == 0) {
-               goto yy384;
+               goto yy403;
        } else {
-               goto yy387;
+               goto yy406;
        }
-yy410:
+yy429:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy409;
-               if (yych <= '9') goto yy415;
-               goto yy409;
+               if (yych <= '/') goto yy428;
+               if (yych <= '9') goto yy434;
+               goto yy428;
        } else {
-               if (yych <= 'F') goto yy415;
-               if (yych <= '`') goto yy409;
-               if (yych <= 'f') goto yy415;
-               goto yy409;
+               if (yych <= 'F') goto yy434;
+               if (yych <= '`') goto yy428;
+               if (yych <= 'f') goto yy434;
+               goto yy428;
        }
-yy411:
+yy430:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy409;
-               if (yych <= '9') goto yy416;
-               goto yy409;
+               if (yych <= '/') goto yy428;
+               if (yych <= '9') goto yy435;
+               goto yy428;
        } else {
-               if (yych <= 'F') goto yy416;
-               if (yych <= '`') goto yy409;
-               if (yych <= 'f') goto yy416;
-               goto yy409;
+               if (yych <= 'F') goto yy435;
+               if (yych <= '`') goto yy428;
+               if (yych <= 'f') goto yy435;
+               goto yy428;
        }
-yy412:
+yy431:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy409;
-               if (yych <= '9') goto yy417;
-               goto yy409;
+               if (yych <= '/') goto yy428;
+               if (yych <= '9') goto yy436;
+               goto yy428;
        } else {
-               if (yych <= 'F') goto yy417;
-               if (yych <= '`') goto yy409;
-               if (yych <= 'f') goto yy417;
-               goto yy409;
+               if (yych <= 'F') goto yy436;
+               if (yych <= '`') goto yy428;
+               if (yych <= 'f') goto yy436;
+               goto yy428;
        }
-yy413:
+yy432:
        ++YYCURSOR;
-#line 475 "../src/ast/lex.re"
+#line 455 "../src/ast/lex.re"
        { return unesc_oct(tok, cur); }
-#line 2359 "src/ast/lex.cc"
-yy415:
+#line 2397 "src/ast/lex.cc"
+yy434:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy409;
-               if (yych <= '9') goto yy419;
-               goto yy409;
+               if (yych <= '/') goto yy428;
+               if (yych <= '9') goto yy438;
+               goto yy428;
        } else {
-               if (yych <= 'F') goto yy419;
-               if (yych <= '`') goto yy409;
-               if (yych <= 'f') goto yy419;
-               goto yy409;
+               if (yych <= 'F') goto yy438;
+               if (yych <= '`') goto yy428;
+               if (yych <= 'f') goto yy438;
+               goto yy428;
        }
-yy416:
+yy435:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy409;
-               if (yych <= '9') goto yy412;
-               goto yy409;
+               if (yych <= '/') goto yy428;
+               if (yych <= '9') goto yy431;
+               goto yy428;
        } else {
-               if (yych <= 'F') goto yy412;
-               if (yych <= '`') goto yy409;
-               if (yych <= 'f') goto yy412;
-               goto yy409;
+               if (yych <= 'F') goto yy431;
+               if (yych <= '`') goto yy428;
+               if (yych <= 'f') goto yy431;
+               goto yy428;
        }
-yy417:
+yy436:
        ++YYCURSOR;
-#line 474 "../src/ast/lex.re"
+#line 454 "../src/ast/lex.re"
        { return unesc_hex(tok, cur); }
-#line 2388 "src/ast/lex.cc"
-yy419:
+#line 2426 "src/ast/lex.cc"
+yy438:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy409;
-               if (yych >= ':') goto yy409;
+               if (yych <= '/') goto yy428;
+               if (yych >= ':') goto yy428;
        } else {
-               if (yych <= 'F') goto yy420;
-               if (yych <= '`') goto yy409;
-               if (yych >= 'g') goto yy409;
+               if (yych <= 'F') goto yy439;
+               if (yych <= '`') goto yy428;
+               if (yych >= 'g') goto yy428;
        }
-yy420:
+yy439:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy409;
-               if (yych <= '9') goto yy411;
-               goto yy409;
+               if (yych <= '/') goto yy428;
+               if (yych <= '9') goto yy430;
+               goto yy428;
        } else {
-               if (yych <= 'F') goto yy411;
-               if (yych <= '`') goto yy409;
-               if (yych <= 'f') goto yy411;
-               goto yy409;
+               if (yych <= 'F') goto yy430;
+               if (yych <= '`') goto yy428;
+               if (yych <= 'f') goto yy430;
+               goto yy428;
        }
 }
-#line 490 "../src/ast/lex.re"
+#line 470 "../src/ast/lex.re"
 
 }
 
@@ -2418,289 +2456,298 @@ uint32_t Scanner::lex_str_chr(char quote, bool &end)
     tok = cur;
     const uint32_t l = get_cline(), c = get_column();
     
-#line 2422 "src/ast/lex.cc"
+#line 2460 "src/ast/lex.cc"
 {
        YYCTYPE yych;
        unsigned int yyaccept = 0;
        if ((YYLIMIT - YYCURSOR) < 10) YYFILL(10);
        yych = (YYCTYPE)*YYCURSOR;
        if (yych <= '\f') {
-               if (yych == '\n') goto yy425;
+               if (yych <= 0x00) goto yy442;
+               if (yych == '\n') goto yy446;
+               goto yy444;
        } else {
-               if (yych <= '\r') goto yy427;
-               if (yych == '\\') goto yy428;
+               if (yych <= '\r') goto yy448;
+               if (yych == '\\') goto yy449;
+               goto yy444;
        }
+yy442:
        ++YYCURSOR;
-yy424:
-#line 505 "../src/ast/lex.re"
+#line 480 "../src/ast/lex.re"
+       { fail_if_eof(); return 0; }
+#line 2479 "src/ast/lex.cc"
+yy444:
+       ++YYCURSOR;
+yy445:
+#line 486 "../src/ast/lex.re"
        {
             end = tok[0] == quote;
             return static_cast<uint8_t>(tok[0]);
         }
-#line 2441 "src/ast/lex.cc"
-yy425:
+#line 2488 "src/ast/lex.cc"
+yy446:
        ++YYCURSOR;
-#line 500 "../src/ast/lex.re"
+#line 481 "../src/ast/lex.re"
        { fatal_lc(l, c, "newline in character string"); }
-#line 2446 "src/ast/lex.cc"
-yy427:
+#line 2493 "src/ast/lex.cc"
+yy448:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy425;
-       goto yy424;
-yy428:
+       if (yych == '\n') goto yy446;
+       goto yy445;
+yy449:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '`') {
                if (yych <= '7') {
                        if (yych <= '\f') {
-                               if (yych == '\n') goto yy425;
+                               if (yych == '\n') goto yy446;
                        } else {
-                               if (yych <= '\r') goto yy431;
-                               if (yych <= '/') goto yy429;
-                               if (yych <= '3') goto yy432;
-                               goto yy434;
+                               if (yych <= '\r') goto yy452;
+                               if (yych <= '/') goto yy450;
+                               if (yych <= '3') goto yy453;
+                               goto yy455;
                        }
                } else {
                        if (yych <= 'W') {
-                               if (yych == 'U') goto yy435;
+                               if (yych == 'U') goto yy456;
                        } else {
-                               if (yych <= 'X') goto yy437;
-                               if (yych == '\\') goto yy438;
+                               if (yych <= 'X') goto yy458;
+                               if (yych == '\\') goto yy459;
                        }
                }
        } else {
                if (yych <= 'q') {
                        if (yych <= 'e') {
-                               if (yych <= 'a') goto yy440;
-                               if (yych <= 'b') goto yy442;
+                               if (yych <= 'a') goto yy461;
+                               if (yych <= 'b') goto yy463;
                        } else {
-                               if (yych <= 'f') goto yy444;
-                               if (yych == 'n') goto yy446;
+                               if (yych <= 'f') goto yy465;
+                               if (yych == 'n') goto yy467;
                        }
                } else {
                        if (yych <= 'u') {
-                               if (yych <= 'r') goto yy448;
-                               if (yych <= 's') goto yy429;
-                               if (yych <= 't') goto yy450;
-                               goto yy437;
+                               if (yych <= 'r') goto yy469;
+                               if (yych <= 's') goto yy450;
+                               if (yych <= 't') goto yy471;
+                               goto yy458;
                        } else {
-                               if (yych <= 'v') goto yy452;
-                               if (yych == 'x') goto yy454;
+                               if (yych <= 'v') goto yy473;
+                               if (yych == 'x') goto yy475;
                        }
                }
        }
-yy429:
+yy450:
        ++YYCURSOR;
-yy430:
-#line 519 "../src/ast/lex.re"
+yy451:
+#line 500 "../src/ast/lex.re"
        {
             if (tok[1] != quote) {
                 warn.useless_escape(cline, get_column(), tok[1]);
             }
             return static_cast<uint8_t>(tok[1]);
         }
-#line 2502 "src/ast/lex.cc"
-yy431:
+#line 2549 "src/ast/lex.cc"
+yy452:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy425;
-       goto yy430;
-yy432:
+       if (yych == '\n') goto yy446;
+       goto yy451;
+yy453:
        yyaccept = 0;
        yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
-       if (yych <= '/') goto yy433;
-       if (yych <= '7') goto yy455;
-yy433:
-#line 502 "../src/ast/lex.re"
+       if (yych <= '/') goto yy454;
+       if (yych <= '7') goto yy476;
+yy454:
+#line 483 "../src/ast/lex.re"
        { fatal_lc(l, c, "syntax error in octal escape sequence"); }
-#line 2515 "src/ast/lex.cc"
-yy434:
+#line 2562 "src/ast/lex.cc"
+yy455:
        ++YYCURSOR;
-       goto yy433;
-yy435:
+       goto yy454;
+yy456:
        yyaccept = 1;
        yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
        if (yych <= '@') {
-               if (yych <= '/') goto yy436;
-               if (yych <= '9') goto yy457;
+               if (yych <= '/') goto yy457;
+               if (yych <= '9') goto yy478;
        } else {
-               if (yych <= 'F') goto yy457;
-               if (yych <= '`') goto yy436;
-               if (yych <= 'f') goto yy457;
+               if (yych <= 'F') goto yy478;
+               if (yych <= '`') goto yy457;
+               if (yych <= 'f') goto yy478;
        }
-yy436:
-#line 501 "../src/ast/lex.re"
+yy457:
+#line 482 "../src/ast/lex.re"
        { fatal_lc(l, c, "syntax error in hexadecimal escape sequence"); }
-#line 2533 "src/ast/lex.cc"
-yy437:
+#line 2580 "src/ast/lex.cc"
+yy458:
        yyaccept = 1;
        yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
        if (yych <= '@') {
-               if (yych <= '/') goto yy436;
-               if (yych <= '9') goto yy458;
-               goto yy436;
+               if (yych <= '/') goto yy457;
+               if (yych <= '9') goto yy479;
+               goto yy457;
        } else {
-               if (yych <= 'F') goto yy458;
-               if (yych <= '`') goto yy436;
-               if (yych <= 'f') goto yy458;
-               goto yy436;
+               if (yych <= 'F') goto yy479;
+               if (yych <= '`') goto yy457;
+               if (yych <= 'f') goto yy479;
+               goto yy457;
        }
-yy438:
+yy459:
        ++YYCURSOR;
-#line 518 "../src/ast/lex.re"
+#line 499 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\\'); }
-#line 2551 "src/ast/lex.cc"
-yy440:
+#line 2598 "src/ast/lex.cc"
+yy461:
        ++YYCURSOR;
-#line 511 "../src/ast/lex.re"
+#line 492 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\a'); }
-#line 2556 "src/ast/lex.cc"
-yy442:
+#line 2603 "src/ast/lex.cc"
+yy463:
        ++YYCURSOR;
-#line 512 "../src/ast/lex.re"
+#line 493 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\b'); }
-#line 2561 "src/ast/lex.cc"
-yy444:
+#line 2608 "src/ast/lex.cc"
+yy465:
        ++YYCURSOR;
-#line 513 "../src/ast/lex.re"
+#line 494 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\f'); }
-#line 2566 "src/ast/lex.cc"
-yy446:
+#line 2613 "src/ast/lex.cc"
+yy467:
        ++YYCURSOR;
-#line 514 "../src/ast/lex.re"
+#line 495 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\n'); }
-#line 2571 "src/ast/lex.cc"
-yy448:
+#line 2618 "src/ast/lex.cc"
+yy469:
        ++YYCURSOR;
-#line 515 "../src/ast/lex.re"
+#line 496 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\r'); }
-#line 2576 "src/ast/lex.cc"
-yy450:
+#line 2623 "src/ast/lex.cc"
+yy471:
        ++YYCURSOR;
-#line 516 "../src/ast/lex.re"
+#line 497 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\t'); }
-#line 2581 "src/ast/lex.cc"
-yy452:
+#line 2628 "src/ast/lex.cc"
+yy473:
        ++YYCURSOR;
-#line 517 "../src/ast/lex.re"
+#line 498 "../src/ast/lex.re"
        { return static_cast<uint8_t>('\v'); }
-#line 2586 "src/ast/lex.cc"
-yy454:
+#line 2633 "src/ast/lex.cc"
+yy475:
        yyaccept = 1;
        yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
        if (yych <= '@') {
-               if (yych <= '/') goto yy436;
-               if (yych <= '9') goto yy459;
-               goto yy436;
+               if (yych <= '/') goto yy457;
+               if (yych <= '9') goto yy480;
+               goto yy457;
        } else {
-               if (yych <= 'F') goto yy459;
-               if (yych <= '`') goto yy436;
-               if (yych <= 'f') goto yy459;
-               goto yy436;
+               if (yych <= 'F') goto yy480;
+               if (yych <= '`') goto yy457;
+               if (yych <= 'f') goto yy480;
+               goto yy457;
        }
-yy455:
+yy476:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych <= '/') goto yy456;
-       if (yych <= '7') goto yy460;
-yy456:
+       if (yych <= '/') goto yy477;
+       if (yych <= '7') goto yy481;
+yy477:
        YYCURSOR = YYMARKER;
        if (yyaccept == 0) {
-               goto yy433;
+               goto yy454;
        } else {
-               goto yy436;
+               goto yy457;
        }
-yy457:
+yy478:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy456;
-               if (yych <= '9') goto yy462;
-               goto yy456;
+               if (yych <= '/') goto yy477;
+               if (yych <= '9') goto yy483;
+               goto yy477;
        } else {
-               if (yych <= 'F') goto yy462;
-               if (yych <= '`') goto yy456;
-               if (yych <= 'f') goto yy462;
-               goto yy456;
+               if (yych <= 'F') goto yy483;
+               if (yych <= '`') goto yy477;
+               if (yych <= 'f') goto yy483;
+               goto yy477;
        }
-yy458:
+yy479:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy456;
-               if (yych <= '9') goto yy463;
-               goto yy456;
+               if (yych <= '/') goto yy477;
+               if (yych <= '9') goto yy484;
+               goto yy477;
        } else {
-               if (yych <= 'F') goto yy463;
-               if (yych <= '`') goto yy456;
-               if (yych <= 'f') goto yy463;
-               goto yy456;
+               if (yych <= 'F') goto yy484;
+               if (yych <= '`') goto yy477;
+               if (yych <= 'f') goto yy484;
+               goto yy477;
        }
-yy459:
+yy480:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy456;
-               if (yych <= '9') goto yy464;
-               goto yy456;
+               if (yych <= '/') goto yy477;
+               if (yych <= '9') goto yy485;
+               goto yy477;
        } else {
-               if (yych <= 'F') goto yy464;
-               if (yych <= '`') goto yy456;
-               if (yych <= 'f') goto yy464;
-               goto yy456;
+               if (yych <= 'F') goto yy485;
+               if (yych <= '`') goto yy477;
+               if (yych <= 'f') goto yy485;
+               goto yy477;
        }
-yy460:
+yy481:
        ++YYCURSOR;
-#line 510 "../src/ast/lex.re"
+#line 491 "../src/ast/lex.re"
        { return unesc_oct(tok, cur); }
-#line 2651 "src/ast/lex.cc"
-yy462:
+#line 2698 "src/ast/lex.cc"
+yy483:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy456;
-               if (yych <= '9') goto yy466;
-               goto yy456;
+               if (yych <= '/') goto yy477;
+               if (yych <= '9') goto yy487;
+               goto yy477;
        } else {
-               if (yych <= 'F') goto yy466;
-               if (yych <= '`') goto yy456;
-               if (yych <= 'f') goto yy466;
-               goto yy456;
+               if (yych <= 'F') goto yy487;
+               if (yych <= '`') goto yy477;
+               if (yych <= 'f') goto yy487;
+               goto yy477;
        }
-yy463:
+yy484:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy456;
-               if (yych <= '9') goto yy459;
-               goto yy456;
+               if (yych <= '/') goto yy477;
+               if (yych <= '9') goto yy480;
+               goto yy477;
        } else {
-               if (yych <= 'F') goto yy459;
-               if (yych <= '`') goto yy456;
-               if (yych <= 'f') goto yy459;
-               goto yy456;
+               if (yych <= 'F') goto yy480;
+               if (yych <= '`') goto yy477;
+               if (yych <= 'f') goto yy480;
+               goto yy477;
        }
-yy464:
+yy485:
        ++YYCURSOR;
-#line 509 "../src/ast/lex.re"
+#line 490 "../src/ast/lex.re"
        { return unesc_hex(tok, cur); }
-#line 2680 "src/ast/lex.cc"
-yy466:
+#line 2727 "src/ast/lex.cc"
+yy487:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy456;
-               if (yych >= ':') goto yy456;
+               if (yych <= '/') goto yy477;
+               if (yych >= ':') goto yy477;
        } else {
-               if (yych <= 'F') goto yy467;
-               if (yych <= '`') goto yy456;
-               if (yych >= 'g') goto yy456;
+               if (yych <= 'F') goto yy488;
+               if (yych <= '`') goto yy477;
+               if (yych >= 'g') goto yy477;
        }
-yy467:
+yy488:
        yych = (YYCTYPE)*++YYCURSOR;
        if (yych <= '@') {
-               if (yych <= '/') goto yy456;
-               if (yych <= '9') goto yy458;
-               goto yy456;
+               if (yych <= '/') goto yy477;
+               if (yych <= '9') goto yy479;
+               goto yy477;
        } else {
-               if (yych <= 'F') goto yy458;
-               if (yych <= '`') goto yy456;
-               if (yych <= 'f') goto yy458;
-               goto yy456;
+               if (yych <= 'F') goto yy479;
+               if (yych <= '`') goto yy477;
+               if (yych <= 'f') goto yy479;
+               goto yy477;
        }
 }
-#line 525 "../src/ast/lex.re"
+#line 506 "../src/ast/lex.re"
 
 }
 
@@ -2720,7 +2767,7 @@ void Scanner::set_sourceline ()
 sourceline:
     tok = cur;
 
-#line 2724 "src/ast/lex.cc"
+#line 2771 "src/ast/lex.cc"
 {
        YYCTYPE yych;
        static const unsigned char yybm[] = {
@@ -2761,101 +2808,109 @@ sourceline:
        yych = (YYCTYPE)*YYCURSOR;
        if (yych <= '\r') {
                if (yych <= '\t') {
-                       if (yych >= 0x01) goto yy472;
+                       if (yych >= 0x01) goto yy493;
                } else {
-                       if (yych <= '\n') goto yy474;
-                       if (yych <= '\f') goto yy472;
-                       goto yy476;
+                       if (yych <= '\n') goto yy495;
+                       if (yych <= '\f') goto yy493;
+                       goto yy497;
                }
        } else {
                if (yych <= '"') {
-                       if (yych <= '!') goto yy472;
-                       goto yy477;
+                       if (yych <= '!') goto yy493;
+                       goto yy498;
                } else {
-                       if (yych <= '0') goto yy472;
-                       if (yych <= '9') goto yy478;
-                       goto yy472;
+                       if (yych <= '0') goto yy493;
+                       if (yych <= '9') goto yy499;
+                       goto yy493;
                }
        }
        ++YYCURSOR;
-#line 562 "../src/ast/lex.re"
+#line 543 "../src/ast/lex.re"
        {
         --cur;
         tok = cur;
         return;
     }
-#line 2788 "src/ast/lex.cc"
-yy472:
+#line 2835 "src/ast/lex.cc"
+yy493:
        ++YYCURSOR;
-yy473:
-#line 568 "../src/ast/lex.re"
+yy494:
+#line 549 "../src/ast/lex.re"
        { goto sourceline; }
-#line 2794 "src/ast/lex.cc"
-yy474:
+#line 2841 "src/ast/lex.cc"
+yy495:
        ++YYCURSOR;
-#line 557 "../src/ast/lex.re"
+#line 538 "../src/ast/lex.re"
        {
         tok = cur;
         return;
     }
-#line 2802 "src/ast/lex.cc"
-yy476:
+#line 2849 "src/ast/lex.cc"
+yy497:
        yych = (YYCTYPE)*++YYCURSOR;
-       if (yych == '\n') goto yy474;
-       goto yy473;
-yy477:
+       if (yych == '\n') goto yy495;
+       goto yy494;
+yy498:
        yych = (YYCTYPE)*(YYMARKER = ++YYCURSOR);
-       if (yych <= 0x00) goto yy473;
-       if (yych == '\n') goto yy473;
-       goto yy482;
-yy478:
+       if (yych <= 0x00) goto yy494;
+       if (yych == '\n') goto yy494;
+       goto yy503;
+yy499:
        ++YYCURSOR;
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = (YYCTYPE)*YYCURSOR;
        if (yybm[0+yych] & 64) {
-               goto yy478;
+               goto yy499;
        }
-#line 544 "../src/ast/lex.re"
+#line 525 "../src/ast/lex.re"
        {
         if (!s_to_u32_unsafe (tok, cur, cline)) {
             fatal_lc(get_cline(), get_column(), "line number overflow");
         }
         goto sourceline;
     }
-#line 2826 "src/ast/lex.cc"
-yy481:
+#line 2873 "src/ast/lex.cc"
+yy502:
        ++YYCURSOR;
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = (YYCTYPE)*YYCURSOR;
-yy482:
+yy503:
        if (yybm[0+yych] & 128) {
-               goto yy481;
+               goto yy502;
        }
-       if (yych <= '\n') goto yy483;
-       if (yych <= '"') goto yy484;
-       goto yy486;
-yy483:
+       if (yych <= '\n') goto yy504;
+       if (yych <= '"') goto yy505;
+       goto yy507;
+yy504:
        YYCURSOR = YYMARKER;
-       goto yy473;
-yy484:
+       goto yy494;
+yy505:
        ++YYCURSOR;
-#line 551 "../src/ast/lex.re"
+#line 532 "../src/ast/lex.re"
        {
         in.escaped_file_name = std::string (tok + 1, tok_len () - 2); // strip quotes
         strrreplace (in.escaped_file_name, "\\", "\\\\");
         goto sourceline;
     }
-#line 2849 "src/ast/lex.cc"
-yy486:
+#line 2896 "src/ast/lex.cc"
+yy507:
        ++YYCURSOR;
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = (YYCTYPE)*YYCURSOR;
-       if (yych <= 0x00) goto yy483;
-       if (yych == '\n') goto yy483;
-       goto yy481;
+       if (yych <= 0x00) goto yy504;
+       if (yych == '\n') goto yy504;
+       goto yy502;
+}
+#line 550 "../src/ast/lex.re"
+
 }
-#line 569 "../src/ast/lex.re"
 
+void Scanner::fail_if_eof() const
+{
+    if (cur == eof) {
+        const uint32_t col = static_cast<uint32_t>(cur - pos) - 1;
+        fatal_lc(get_cline(), col, "unexpected end of input");
+    }
 }
 
 } // end namespace re2c
index 3fac34cd4eeb912230b1d3121dfeee97f76c5e8b..3f7fb3cad48e297532b4c1ea09329142c5c21071 100644 (file)
@@ -49,6 +49,7 @@ space   = [ \t];
 ws      = (space | [\r\n]);
 eol     = "\r"? "\n";
 eoc     = "*" "/";
+linedir = eol space* "#" space* "line" space+;
 lineinf = lineno (space+ dstring)? eol;
 
     esc = "\\";
@@ -139,7 +140,7 @@ echo:
         return Stop;
     }
 
-    eol space* "#" space* "line" space+ / lineinf {
+    linedir / lineinf {
         out.wraw(tok, ptr + 1);
         set_sourceline();
         goto echo;
@@ -199,8 +200,8 @@ scan:
     tchar = cur - pos;
     tok = cur;
 /*!re2c
-    "{"        { lex_code(1); return TOKEN_CODE; }
-    ":="       { tok += 2; lex_code(0); return TOKEN_CODE; }
+    "{"        { lex_code_multiline(); return TOKEN_CODE; }
+    ":="       { tok += 2; lex_code_oneline(); return TOKEN_CODE; }
     ":" / "=>" { return *tok; }
 
     "//" { lex_cpp_comment(); goto scan; }
@@ -305,13 +306,12 @@ scan:
 
     space+ { goto scan; }
 
-    eol space* "#" space* "line" space+ / lineinf {
+    linedir / lineinf {
         set_sourceline ();
         return TOKEN_LINE_INFO;
     }
 
     eol {
-        if (cur == eof) return 0;
         pos = cur;
         cline++;
         if (lexer_state == LEX_FLEX_NAME) {
@@ -330,71 +330,50 @@ scan:
 */
 }
 
-void Scanner::lex_code(uint32_t depth)
+void Scanner::lex_code_oneline()
 {
     const uint32_t line = cline;
 code:
 /*!re2c
-    "}" {
-        if (depth == 0) {
-            fatal_l(get_cline(), "Curly braces are not allowed after ':='");
-        }
-        else if (--depth == 0) {
-            yylval.code = new Code(get_fname (), line, tok, tok_len ());
-            return;
-        }
-        goto code;
-    }
-
-    "{" {
-        if (depth == 0) {
-            fatal_l(get_cline(), "Curly braces are not allowed after ':='");
-        }
-        else {
-            ++depth;
-        }
-        goto code;
-    }
-
-    eol space* "#" space* "line" space+ / lineinf {
-        set_sourceline ();
-        goto code;
+    eol / ws { goto code; }
+    eol {
+        tok += strspn(tok, " \t\r\n");
+        while (cur > tok && strchr(" \t\r\n", cur[-1])) --cur;
+        yylval.code = new Code(get_fname (), line, tok, tok_len ());
+        return;
     }
 
-    eol / ws {
-        if (depth == 0) goto code;
-        else if (cur == eof) fatal_l(get_cline(), "missing '}'");
-        pos = cur;
-        cline++;
-        goto code;
-    }
+    eof      { fail_if_eof(); goto code; }
+    [{}]     { fatal_l(get_cline(), "Curly braces are not allowed after ':='"); }
+    "/*"     { lex_c_comment(); goto code; }
+    "//"     { lex_cpp_comment(); goto code; }
+    ["']     { lex_string(cur[-1]); goto code; }
+    *        { goto code; }
+*/
+}
 
-    eol {
-        if (depth == 0) {
-            tok += strspn(tok, " \t\r\n");
-            while (cur > tok && strchr(" \t\r\n", cur[-1])) --cur;
+void Scanner::lex_code_multiline()
+{
+    const uint32_t line = cline;
+    uint32_t depth = 1;
+code:
+/*!re2c
+    "}" {
+        if (--depth == 0) {
             yylval.code = new Code(get_fname (), line, tok, tok_len ());
             return;
         }
-        else if (cur == eof) {
-            fatal_l(get_cline(), "missing '}'");
-        }
-        pos = cur;
-        cline++;
-        goto code;
-    }
-
-    eof {
-        if (cur == eof) {
-            if (depth) fatal_l(get_cline(), "missing '}'");
-        }
         goto code;
     }
 
-    "/*" { lex_c_comment(); goto code; }
-    "//" { lex_cpp_comment(); goto code; }
-    ["'] { lex_string(cur[-1]); goto code; }
-    *    { goto code; }
+    "{"               { ++depth; goto code; }
+    linedir / lineinf { set_sourceline (); goto code; }
+    eol               { pos = cur; cline++; goto code; }
+    eof               { fail_if_eof(); goto code; }
+    "/*"              { lex_c_comment(); goto code; }
+    "//"              { lex_cpp_comment(); goto code; }
+    ["']              { lex_string(cur[-1]); goto code; }
+    *                 { goto code; }
 */
 }
 
@@ -405,7 +384,7 @@ loop:
     ["']       { if (cur[-1] == delim) return; else goto loop; }
     esc [\\"'] { goto loop; }
     eol        { pos = cur; ++cline; goto loop; }
-    eof        { if (cur == eof) fatal_l(get_cline(), "unexpected end of input"); else goto loop; }
+    eof        { fail_if_eof(); goto loop; }
     *          { goto loop; }
 */
 }
@@ -416,7 +395,7 @@ loop:
 /*!re2c
     eoc { return; }
     eol { pos = cur; ++cline; goto loop; }
-    eof { if (cur == eof) fatal_l(get_cline(), "end of input in comment"); else goto loop; }
+    eof { fail_if_eof(); goto loop; }
     *   { goto loop; }
 */
 }
@@ -426,7 +405,7 @@ void Scanner::lex_cpp_comment()
 loop:
 /*!re2c
     eol { pos = cur; ++cline; return; }
-    eof { if (cur == eof) fatal_l(get_cline(), "end of input in comment"); else goto loop; }
+    eof { fail_if_eof(); goto loop; }
     *   { goto loop; }
 */
 }
@@ -465,6 +444,7 @@ uint32_t Scanner::lex_cls_chr()
     const uint32_t l = get_cline(), c = get_column();
     /*!re2c
         *          { fatal_lc(l, c, "syntax error"); }
+        eof        { fail_if_eof(); return 0; }
         esc? eol   { fatal_lc(l, c, "newline in character class"); }
         esc [xXuU] { fatal_lc(l, c, "syntax error in hexadecimal escape sequence"); }
         esc [0-7]  { fatal_lc(l, c, "syntax error in octal escape sequence"); }
@@ -497,6 +477,7 @@ uint32_t Scanner::lex_str_chr(char quote, bool &end)
     const uint32_t l = get_cline(), c = get_column();
     /*!re2c
         *          { fatal_lc(l, c, "syntax error"); }
+        eof        { fail_if_eof(); return 0; }
         esc? eol   { fatal_lc(l, c, "newline in character string"); }
         esc [xXuU] { fatal_lc(l, c, "syntax error in hexadecimal escape sequence"); }
         esc [0-7]  { fatal_lc(l, c, "syntax error in octal escape sequence"); }
@@ -569,4 +550,12 @@ sourceline:
 */
 }
 
+void Scanner::fail_if_eof() const
+{
+    if (cur == eof) {
+        const uint32_t col = static_cast<uint32_t>(cur - pos) - 1;
+        fatal_lc(get_cline(), col, "unexpected end of input");
+    }
+}
+
 } // end namespace re2c
index fe35962ec4dbc63932cd46ad146e4e63963a3b81..1b30c0c9c6666c7821b9de0a4a12e0a9d68b14b4 100644 (file)
@@ -62,7 +62,8 @@ class Scanner: private ScannerState
 
     void fill(uint32_t need);
     void lex_end_of_comment(OutputFile &out);
-    void lex_code(uint32_t depth);
+    void lex_code_oneline();
+    void lex_code_multiline();
     void lex_c_comment();
     void lex_cpp_comment();
     void lex_string(char delim);
@@ -82,7 +83,8 @@ class Scanner: private ScannerState
     int32_t lex_conf_number();
     bool lex_conf_bool();
     std::string lex_conf_string();
-    size_t tok_len () const;
+    size_t tok_len() const;
+    void fail_if_eof() const;
 
 public:
     enum ParseMode {Stop, Parse, Reuse, Rules};
diff --git a/re2c/test/american_fuzzy_lop/001.c b/re2c/test/american_fuzzy_lop/001.c
new file mode 100644 (file)
index 0000000..1abbbad
--- /dev/null
@@ -0,0 +1 @@
+re2c: error: line 1, column 4: unexpected end of input
diff --git a/re2c/test/american_fuzzy_lop/002.c b/re2c/test/american_fuzzy_lop/002.c
new file mode 100644 (file)
index 0000000..4fb4d3c
--- /dev/null
@@ -0,0 +1 @@
+re2c: error: line 1, column 3: unexpected end of input
diff --git a/re2c/test/american_fuzzy_lop/002.re b/re2c/test/american_fuzzy_lop/002.re
new file mode 100644 (file)
index 0000000..4c522bd
--- /dev/null
@@ -0,0 +1 @@
+%{[
\ No newline at end of file
diff --git a/re2c/test/american_fuzzy_lop/003.c b/re2c/test/american_fuzzy_lop/003.c
new file mode 100644 (file)
index 0000000..4fb4d3c
--- /dev/null
@@ -0,0 +1 @@
+re2c: error: line 1, column 3: unexpected end of input
diff --git a/re2c/test/american_fuzzy_lop/003.re b/re2c/test/american_fuzzy_lop/003.re
new file mode 100644 (file)
index 0000000..e7c0b40
--- /dev/null
@@ -0,0 +1 @@
+%{"
\ No newline at end of file
diff --git a/re2c/test/american_fuzzy_lop/01.c b/re2c/test/american_fuzzy_lop/01.c
deleted file mode 100644 (file)
index b62aa5f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-re2c: error: line 1: unexpected end of input
index efbd10e85c2049dbd981c6981400163f4ea02a5a..996ceb6b12666c9b627828f3befa347644e17507 100644 (file)
@@ -1 +1 @@
-re2c: error: line 5: missing '}'
+re2c: error: line 5, column 0: unexpected end of input