Commit b828e3d0 authored by jan.koester's avatar jan.koester
Browse files

bison fix

parent a06cbcd2
Loading
Loading
Loading
Loading
+50 −5
Changes for lib/bison/bison.cpp: 50 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -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())
@@ -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
@@ -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";
@@ -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
@@ -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";
@@ -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";

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 ]