Loading lib/bison/bison.cpp +50 −5 Changes for lib/bison/bison.cpp: 50 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -218,6 +218,11 @@ bool GrammarReader::read(Grammar &out){ g_->terminals.push_back(endTok); g_->symbolIndex["$end"]=0; // "error" is always there: real bison's token 256, what recovery shifts Terminal errorTok; errorTok.name="error"; errorTok.id=1; errorTok.externalCode=256; g_->terminals.push_back(errorTok); g_->symbolIndex["error"]=1; Nonterminal acceptNT; acceptNT.name="$accept"; acceptNT.id=-1; // finalized to numTerminals()+0 once declarations are done (see the // "Finalize nonterminal ids" pass in parseRulesSection()) Loading Loading @@ -1473,7 +1478,10 @@ std::string CodeGenerator::generateSource(const CodegenOptions &opts) const { out += "\n#define YY_ACCEPT_CODE 2147483647\n"; out += "#define YYEMPTY (-2)\n"; out += "#define YYEOF 0\n"; out += "#define yyclearin (yychar = YYEMPTY)\n\n"; out += "#define YY_ERROR_TOKEN 1\n"; out += "#define yyclearin (yychar = YYEMPTY)\n"; out += "#define yyerrok (yyerrstatus = 0)\n"; out += "#define YYRECOVERING() (!!yyerrstatus)\n\n"; if(g_.locations){ // also for a grammar's own YYLLOC_DEFAULT, which is written with it Loading Loading @@ -1581,7 +1589,8 @@ std::string CodeGenerator::generateSource(const CodegenOptions &opts) const { } if(g_.pureParser) out += " int yynerrs = 0;\n"; out += " yychar = YYEMPTY;\n"; out += " int yylen;\n"; out += " int yylen = 0;\n"; out += " int yyerrstatus = 0;\n"; out += " size_t yystacksize = 200;\n"; out += " int *yyss = (int*)malloc(sizeof(int)*yystacksize);\n"; out += " YYSTYPE *yyvs = (YYSTYPE*)malloc(sizeof(YYSTYPE)*yystacksize);\n"; Loading @@ -1605,8 +1614,9 @@ std::string CodeGenerator::generateSource(const CodegenOptions &opts) const { out += "#define YYABORT goto yyabortlab\n"; out += "#define YYACCEPT goto yyacceptlab\n"; out += "#define YYERROR goto yyerrlab\n\n"; out += "#define YYERROR goto yyerrorlab\n\n"; out += "yynewstate:\n"; out += " for (;;) {\n"; out += " yystate = *yyssp;\n"; // Arriving at the accept state is, by itself, total proof of a Loading Loading @@ -1662,6 +1672,7 @@ std::string CodeGenerator::generateSource(const CodegenOptions &opts) const { out += " ++yyssp; *yyssp = yyn;\n"; out += " ++yyvsp; *yyvsp = "+lvalName+";\n"; if(g_.locations) out += " ++yylsp; *yylsp = "+llocName+";\n"; out += " if (yyerrstatus) --yyerrstatus;\n"; out += " yychar = YYEMPTY;\n"; out += " continue;\n"; out += " }\n\n"; Loading Loading @@ -1704,11 +1715,45 @@ std::string CodeGenerator::generateSource(const CodegenOptions &opts) const { out += " goto yyerrlab;\n"; out += " }\n\n"; // Error recovery as in real bison: report once per error, discard the // token that was already refused right after recovering, pop until a // state can shift "error", and stay quiet until three tokens went well. out += "yyerrlab:\n"; out += " if (!yyerrstatus) {\n"; out += " ++yynerrs;\n"; out += " "+prefixed("yyerror")+"("+errArgs+");\n"; out += " yyresult = 1;\n"; out += " goto yyreturn;\n\n"; out += " }\n"; out += " if (yyerrstatus == 3) {\n"; out += " if (yychar <= YYEOF) { if (yychar == YYEOF) goto yyabortlab; }\n"; out += " else yychar = YYEMPTY;\n"; out += " }\n"; out += " goto yyerrlab1;\n\n"; // YYERROR in an action: the rule's symbols are still on the stack out += "yyerrorlab:\n"; out += " yyssp -= yylen; yyvsp -= yylen;\n"; if(g_.locations) out += " yylsp -= yylen;\n"; out += " yylen = 0;\n\n"; out += "yyerrlab1:\n"; out += " yyerrstatus = 3;\n"; out += " for (;;) {\n"; out += " int yy_off3 = yy_action_offset[*yyssp];\n"; out += " int yy_cnt3 = yy_action_count[*yyssp];\n"; out += " int yy_k3;\n"; out += " yyn = 0;\n"; out += " for (yy_k3 = yy_off3; yy_k3 < yy_off3 + yy_cnt3; ++yy_k3) {\n"; out += " if (yy_action_term[yy_k3] == YY_ERROR_TOKEN) { yyn = yy_action_value[yy_k3]; break; }\n"; out += " }\n"; out += " if (yyn > 0 && yyn != YY_ACCEPT_CODE) break;\n"; out += " if (yyssp == yyss) goto yyabortlab;\n"; out += " --yyssp; --yyvsp;\n"; if(g_.locations) out += " --yylsp;\n"; out += " }\n"; out += " YY_GROW_IF_NEEDED;\n"; out += " ++yyssp; *yyssp = yyn;\n"; out += " ++yyvsp; *yyvsp = "+lvalName+";\n"; if(g_.locations) out += " ++yylsp; *yylsp = "+llocName+";\n"; out += " goto yynewstate;\n\n"; out += "yyabortlab:\n"; out += " yyresult = 1;\n"; out += " goto yyreturn;\n\n"; Loading lib/bison/test/run.sh 0 → 100644 +169 −0 Changes for lib/bison/test/run.sh: 169 added lines, 0 removed lines. Original line number Diff line number Diff line #!/bin/bash # bison test suite: usage: run.sh BISON CC (BISON: the fresh binary's bison applet) BISON=${1:-bison}; CC=${2:-cc} T=$(mktemp -d); trap 'rm -rf "$T"' EXIT pass=0; fail=0 # check NAME YFILE INPUT EXPECTED check() { local name=$1 y=$2 input=$3 want=$4 got if ! (cd "$T" && $BISON -o p.c "$y" 2>err.txt && $CC -std=gnu99 -Wall -Werror=implicit-function-declaration -Wno-unused -o p p.c 2>>err.txt); then echo "FAIL $name (build)"; head -8 "$T/err.txt"; fail=$((fail+1)); return fi got=$(printf "$input" | timeout 5 "$T/p" 2>&1 | head -c 2000) if [ "$got" = "$want" ]; then pass=$((pass+1)); else echo "FAIL $name"; echo " want: $want"; echo " got: $got"; fail=$((fail+1)) fi } # a token per byte: digits are NUM, everything else itself LEX=' #include <ctype.h> #include <stdio.h> int yylex(void){ int c = getchar(); if (c == EOF) return 0; if (isdigit(c)) { yylval.n = c - 48; return NUM; } return c; } int main(void){ int r = yyparse(); printf("=%d", r); return 0; } ' cat > "$T/rec.y" <<E %{ #include <stdio.h> int yylex(void); void yyerror(const char *s); %} %union { int n; } %token <n> NUM %% list: | list line ; line: NUM ';' { printf("[%d]", \$1); } | error ';' { printf("<rec>"); yyerrok; } ; %% void yyerror(const char *s){ printf("E"); } $LEX E check recovery rec.y '1;xx;2;' '[1]E<rec>[2]=0' check one-report-per-error rec.y 'x;y;3;' 'E<rec>E<rec>[3]=0' check unrecoverable-eof rec.y '1;x' '[1]E=1' cat > "$T/quiet.y" <<E %{ #include <stdio.h> int yylex(void); void yyerror(const char *s); %} %union { int n; } %token <n> NUM %% list: | list line ; line: NUM ';' { printf("[%d]", \$1); } | error ';' { printf("<%d>", YYRECOVERING()); } ; %% void yyerror(const char *s){ printf("E"); } $LEX E check quiet-until-three-shifts quiet.y 'x;y;1;2;3;4;' 'E<1><1>[1][2][3][4]=0' cat > "$T/yyerr.y" <<E %{ #include <stdio.h> int yylex(void); void yyerror(const char *s); %} %union { int n; } %token <n> NUM %% list: | list line ; line: NUM ';' { if (\$1 == 7) YYERROR; printf("[%d]", \$1); } | error ';' { printf("<rec>"); yyerrok; } | '!' { YYABORT; } | '.' { YYACCEPT; } ; %% void yyerror(const char *s){ printf("E"); } $LEX E check yyerror-macro yyerr.y '1;7;;2;' '[1]<rec>[2]=0' check yyabort yyerr.y '1;!' '[1]=1' check yyaccept yyerr.y '.' '=0' cat > "$T/clear.y" <<E %{ #include <stdio.h> int yylex(void); void yyerror(const char *s); %} %union { int n; } %token <n> NUM %% list: | list line ; line: NUM ';' { printf("[%d]", \$1); } | error { yyclearin; yyerrok; printf("<c>"); } ; %% void yyerror(const char *s){ printf("E"); } $LEX E check yyclearin clear.y '1;x2;' '[1]E<c>[2]=0' cat > "$T/mid.y" <<E %{ #include <stdio.h> int yylex(void); void yyerror(const char *s); %} %union { int n; char c; } %token <n> NUM %type <n> sum %% top: sum ';' { printf("%d", \$1); } ; sum: NUM { \$<c>\$ = 'x'; } '+' NUM { printf("%c", \$<c>2); \$\$ = \$1 + \$4; } ; %% void yyerror(const char *s){ printf("E"); } $LEX E check explicit-tag+mid-rule mid.y '1+2;' 'x3=0' cat > "$T/pre.y" <<'E' %{ #include <stdio.h> #include <ctype.h> int my_yylex(void); void my_yyerror(const char *s); %} %name-prefix="my_yy" %locations %union { int n; } %token <n> NUM %% top: NUM ';' { printf("%d@%d", $1, @1.first_column); (void) yynerrs; } | NUM error ';' { yyerror("custom"); } ; %% int my_yylex(void){ static int col; int c = getchar(); if (c == EOF) return 0; my_yylloc.first_column = my_yylloc.last_column = col++; if (isdigit(c)) { my_yylval.n = c - 48; return NUM; } return c; } void my_yyerror(const char *s){ printf("{%s}", s); } int main(void){ int r = my_yyparse(); printf("=%d", r); return 0; } E check name-prefix pre.y '5;' '5@0=0' check prefix-error-location-free pre.y '5x;' '{syntax error}{custom}=0' cat > "$T/ownloc.y" <<'E' %{ #include <stdio.h> #include <ctype.h> #define YYLTYPE struct mine struct mine { int first, last; }; #define YYLLOC_DEFAULT(Current, Rhs, N) do { \ (Current).first = YYRHSLOC(Rhs, 1).first; (Current).last = YYRHSLOC(Rhs, N).last; } while (0) int yylex(void); void yyerror(const char *s); %} %locations %% top: 'a' 'b' 'c' { printf("%d-%d", @$.first, @$.last); } ; %% int yylex(void){ static int n; int c = getchar(); if (c == EOF || c == '\n') return 0; yylloc.first = yylloc.last = n++; return c; } void yyerror(const char *s){ printf("E"); } int main(void){ return yyparse(); } E check own-yylloc-default ownloc.y 'abc' '0-2' echo "$pass passed, $fail failed" [ "$fail" = 0 ] Loading
lib/bison/bison.cpp +50 −5 Changes for lib/bison/bison.cpp: 50 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -218,6 +218,11 @@ bool GrammarReader::read(Grammar &out){ g_->terminals.push_back(endTok); g_->symbolIndex["$end"]=0; // "error" is always there: real bison's token 256, what recovery shifts Terminal errorTok; errorTok.name="error"; errorTok.id=1; errorTok.externalCode=256; g_->terminals.push_back(errorTok); g_->symbolIndex["error"]=1; Nonterminal acceptNT; acceptNT.name="$accept"; acceptNT.id=-1; // finalized to numTerminals()+0 once declarations are done (see the // "Finalize nonterminal ids" pass in parseRulesSection()) Loading Loading @@ -1473,7 +1478,10 @@ std::string CodeGenerator::generateSource(const CodegenOptions &opts) const { out += "\n#define YY_ACCEPT_CODE 2147483647\n"; out += "#define YYEMPTY (-2)\n"; out += "#define YYEOF 0\n"; out += "#define yyclearin (yychar = YYEMPTY)\n\n"; out += "#define YY_ERROR_TOKEN 1\n"; out += "#define yyclearin (yychar = YYEMPTY)\n"; out += "#define yyerrok (yyerrstatus = 0)\n"; out += "#define YYRECOVERING() (!!yyerrstatus)\n\n"; if(g_.locations){ // also for a grammar's own YYLLOC_DEFAULT, which is written with it Loading Loading @@ -1581,7 +1589,8 @@ std::string CodeGenerator::generateSource(const CodegenOptions &opts) const { } if(g_.pureParser) out += " int yynerrs = 0;\n"; out += " yychar = YYEMPTY;\n"; out += " int yylen;\n"; out += " int yylen = 0;\n"; out += " int yyerrstatus = 0;\n"; out += " size_t yystacksize = 200;\n"; out += " int *yyss = (int*)malloc(sizeof(int)*yystacksize);\n"; out += " YYSTYPE *yyvs = (YYSTYPE*)malloc(sizeof(YYSTYPE)*yystacksize);\n"; Loading @@ -1605,8 +1614,9 @@ std::string CodeGenerator::generateSource(const CodegenOptions &opts) const { out += "#define YYABORT goto yyabortlab\n"; out += "#define YYACCEPT goto yyacceptlab\n"; out += "#define YYERROR goto yyerrlab\n\n"; out += "#define YYERROR goto yyerrorlab\n\n"; out += "yynewstate:\n"; out += " for (;;) {\n"; out += " yystate = *yyssp;\n"; // Arriving at the accept state is, by itself, total proof of a Loading Loading @@ -1662,6 +1672,7 @@ std::string CodeGenerator::generateSource(const CodegenOptions &opts) const { out += " ++yyssp; *yyssp = yyn;\n"; out += " ++yyvsp; *yyvsp = "+lvalName+";\n"; if(g_.locations) out += " ++yylsp; *yylsp = "+llocName+";\n"; out += " if (yyerrstatus) --yyerrstatus;\n"; out += " yychar = YYEMPTY;\n"; out += " continue;\n"; out += " }\n\n"; Loading Loading @@ -1704,11 +1715,45 @@ std::string CodeGenerator::generateSource(const CodegenOptions &opts) const { out += " goto yyerrlab;\n"; out += " }\n\n"; // Error recovery as in real bison: report once per error, discard the // token that was already refused right after recovering, pop until a // state can shift "error", and stay quiet until three tokens went well. out += "yyerrlab:\n"; out += " if (!yyerrstatus) {\n"; out += " ++yynerrs;\n"; out += " "+prefixed("yyerror")+"("+errArgs+");\n"; out += " yyresult = 1;\n"; out += " goto yyreturn;\n\n"; out += " }\n"; out += " if (yyerrstatus == 3) {\n"; out += " if (yychar <= YYEOF) { if (yychar == YYEOF) goto yyabortlab; }\n"; out += " else yychar = YYEMPTY;\n"; out += " }\n"; out += " goto yyerrlab1;\n\n"; // YYERROR in an action: the rule's symbols are still on the stack out += "yyerrorlab:\n"; out += " yyssp -= yylen; yyvsp -= yylen;\n"; if(g_.locations) out += " yylsp -= yylen;\n"; out += " yylen = 0;\n\n"; out += "yyerrlab1:\n"; out += " yyerrstatus = 3;\n"; out += " for (;;) {\n"; out += " int yy_off3 = yy_action_offset[*yyssp];\n"; out += " int yy_cnt3 = yy_action_count[*yyssp];\n"; out += " int yy_k3;\n"; out += " yyn = 0;\n"; out += " for (yy_k3 = yy_off3; yy_k3 < yy_off3 + yy_cnt3; ++yy_k3) {\n"; out += " if (yy_action_term[yy_k3] == YY_ERROR_TOKEN) { yyn = yy_action_value[yy_k3]; break; }\n"; out += " }\n"; out += " if (yyn > 0 && yyn != YY_ACCEPT_CODE) break;\n"; out += " if (yyssp == yyss) goto yyabortlab;\n"; out += " --yyssp; --yyvsp;\n"; if(g_.locations) out += " --yylsp;\n"; out += " }\n"; out += " YY_GROW_IF_NEEDED;\n"; out += " ++yyssp; *yyssp = yyn;\n"; out += " ++yyvsp; *yyvsp = "+lvalName+";\n"; if(g_.locations) out += " ++yylsp; *yylsp = "+llocName+";\n"; out += " goto yynewstate;\n\n"; out += "yyabortlab:\n"; out += " yyresult = 1;\n"; out += " goto yyreturn;\n\n"; Loading
lib/bison/test/run.sh 0 → 100644 +169 −0 Changes for lib/bison/test/run.sh: 169 added lines, 0 removed lines. Original line number Diff line number Diff line #!/bin/bash # bison test suite: usage: run.sh BISON CC (BISON: the fresh binary's bison applet) BISON=${1:-bison}; CC=${2:-cc} T=$(mktemp -d); trap 'rm -rf "$T"' EXIT pass=0; fail=0 # check NAME YFILE INPUT EXPECTED check() { local name=$1 y=$2 input=$3 want=$4 got if ! (cd "$T" && $BISON -o p.c "$y" 2>err.txt && $CC -std=gnu99 -Wall -Werror=implicit-function-declaration -Wno-unused -o p p.c 2>>err.txt); then echo "FAIL $name (build)"; head -8 "$T/err.txt"; fail=$((fail+1)); return fi got=$(printf "$input" | timeout 5 "$T/p" 2>&1 | head -c 2000) if [ "$got" = "$want" ]; then pass=$((pass+1)); else echo "FAIL $name"; echo " want: $want"; echo " got: $got"; fail=$((fail+1)) fi } # a token per byte: digits are NUM, everything else itself LEX=' #include <ctype.h> #include <stdio.h> int yylex(void){ int c = getchar(); if (c == EOF) return 0; if (isdigit(c)) { yylval.n = c - 48; return NUM; } return c; } int main(void){ int r = yyparse(); printf("=%d", r); return 0; } ' cat > "$T/rec.y" <<E %{ #include <stdio.h> int yylex(void); void yyerror(const char *s); %} %union { int n; } %token <n> NUM %% list: | list line ; line: NUM ';' { printf("[%d]", \$1); } | error ';' { printf("<rec>"); yyerrok; } ; %% void yyerror(const char *s){ printf("E"); } $LEX E check recovery rec.y '1;xx;2;' '[1]E<rec>[2]=0' check one-report-per-error rec.y 'x;y;3;' 'E<rec>E<rec>[3]=0' check unrecoverable-eof rec.y '1;x' '[1]E=1' cat > "$T/quiet.y" <<E %{ #include <stdio.h> int yylex(void); void yyerror(const char *s); %} %union { int n; } %token <n> NUM %% list: | list line ; line: NUM ';' { printf("[%d]", \$1); } | error ';' { printf("<%d>", YYRECOVERING()); } ; %% void yyerror(const char *s){ printf("E"); } $LEX E check quiet-until-three-shifts quiet.y 'x;y;1;2;3;4;' 'E<1><1>[1][2][3][4]=0' cat > "$T/yyerr.y" <<E %{ #include <stdio.h> int yylex(void); void yyerror(const char *s); %} %union { int n; } %token <n> NUM %% list: | list line ; line: NUM ';' { if (\$1 == 7) YYERROR; printf("[%d]", \$1); } | error ';' { printf("<rec>"); yyerrok; } | '!' { YYABORT; } | '.' { YYACCEPT; } ; %% void yyerror(const char *s){ printf("E"); } $LEX E check yyerror-macro yyerr.y '1;7;;2;' '[1]<rec>[2]=0' check yyabort yyerr.y '1;!' '[1]=1' check yyaccept yyerr.y '.' '=0' cat > "$T/clear.y" <<E %{ #include <stdio.h> int yylex(void); void yyerror(const char *s); %} %union { int n; } %token <n> NUM %% list: | list line ; line: NUM ';' { printf("[%d]", \$1); } | error { yyclearin; yyerrok; printf("<c>"); } ; %% void yyerror(const char *s){ printf("E"); } $LEX E check yyclearin clear.y '1;x2;' '[1]E<c>[2]=0' cat > "$T/mid.y" <<E %{ #include <stdio.h> int yylex(void); void yyerror(const char *s); %} %union { int n; char c; } %token <n> NUM %type <n> sum %% top: sum ';' { printf("%d", \$1); } ; sum: NUM { \$<c>\$ = 'x'; } '+' NUM { printf("%c", \$<c>2); \$\$ = \$1 + \$4; } ; %% void yyerror(const char *s){ printf("E"); } $LEX E check explicit-tag+mid-rule mid.y '1+2;' 'x3=0' cat > "$T/pre.y" <<'E' %{ #include <stdio.h> #include <ctype.h> int my_yylex(void); void my_yyerror(const char *s); %} %name-prefix="my_yy" %locations %union { int n; } %token <n> NUM %% top: NUM ';' { printf("%d@%d", $1, @1.first_column); (void) yynerrs; } | NUM error ';' { yyerror("custom"); } ; %% int my_yylex(void){ static int col; int c = getchar(); if (c == EOF) return 0; my_yylloc.first_column = my_yylloc.last_column = col++; if (isdigit(c)) { my_yylval.n = c - 48; return NUM; } return c; } void my_yyerror(const char *s){ printf("{%s}", s); } int main(void){ int r = my_yyparse(); printf("=%d", r); return 0; } E check name-prefix pre.y '5;' '5@0=0' check prefix-error-location-free pre.y '5x;' '{syntax error}{custom}=0' cat > "$T/ownloc.y" <<'E' %{ #include <stdio.h> #include <ctype.h> #define YYLTYPE struct mine struct mine { int first, last; }; #define YYLLOC_DEFAULT(Current, Rhs, N) do { \ (Current).first = YYRHSLOC(Rhs, 1).first; (Current).last = YYRHSLOC(Rhs, N).last; } while (0) int yylex(void); void yyerror(const char *s); %} %locations %% top: 'a' 'b' 'c' { printf("%d-%d", @$.first, @$.last); } ; %% int yylex(void){ static int n; int c = getchar(); if (c == EOF || c == '\n') return 0; yylloc.first = yylloc.last = n++; return c; } void yyerror(const char *s){ printf("E"); } int main(void){ return yyparse(); } E check own-yylloc-default ownloc.y 'abc' '0-2' echo "$pass passed, $fail failed" [ "$fail" = 0 ]