Skip to content

Commit

Permalink
d: change the return value of yylex from int to TokenKind
Browse files Browse the repository at this point in the history
* data/skeletons/lalr1.d: Change the return value.
* examples/d/calc/calc.y, examples/d/simple/calc.y: Adjust.
* tests/scanner.at: Adjust.
* tests/calc.at (_AT_DATA_CALC_Y(d)): New, extracted from...
(_AT_DATA_CALC_Y(c)): here.
The two grammars have been sufficiently different to be separated.
Still trying to be them together results in a maintenance burden.  For
the same reason, instead of specifying the results for D and for the
rest, compute the expected results with D from the regular case.
  • Loading branch information
adelavais authored and akimd committed Sep 26, 2020
1 parent de638df commit f296669
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 38 deletions.
15 changes: 4 additions & 11 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -249,21 +249,14 @@ are. Keep the same variable names. If you change the wording in one place,
do it in the others too. In other words: make sure to keep the
maintenance *simple* by avoiding any gratuitous difference.

** Change the return value of yylex
Historically people were allowed to return any int from the scanner (which
is convenient and allows `return '+'` from the scanner). Akim tends to see
this as an error, we should restrict the return values to TokenKind (not to
be confused with SymbolKind).

In the case of D, without the history, we have the choice to support or not
`int`. If we want to _keep_ `int`, is there a way, say via introspection,
to support both signatures of yylex? If we don't keep `int`, just move to
TokenKind.

** Documentation
Write documentation about D support in doc/bison.texi. Imitate the Java
documentation. You should be more succinct IMHO.

** yyerrok
It appears that neither Java nor D support yyerrok currently. It does not
need to be named this way...

** Complete Symbols
The current interface from the scanner to the parser is somewhat clumsy: the
token kind is returned by yylex, but the value and location are stored in
Expand Down
4 changes: 2 additions & 2 deletions data/skeletons/lalr1.d
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public interface Lexer
* to the next token and prepares to return the semantic value
* ]b4_locations_if([and beginning/ending positions ])[of the token.
* @@return the token identifier corresponding to the next token. */
int yylex ();
TokenKind yylex ();
/**
* Entry point for error reporting. Emits an error
Expand Down Expand Up @@ -272,7 +272,7 @@ b4_user_union_members
yyDebugStream.writeln (s);
}
]])[
private final int yylex () {
private final TokenKind yylex () {
return yylexer.yylex ();
}
Expand Down
2 changes: 1 addition & 1 deletion examples/d/calc/calc.y
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class CalcLexer(R) : Lexer
return semanticVal_;
}

int yylex ()
TokenKind yylex ()
{
import std.uni : isWhite, isNumber;

Expand Down
2 changes: 1 addition & 1 deletion examples/d/simple/calc.y
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class CalcLexer(R) : Lexer
return semanticVal_;
}

int yylex ()
TokenKind yylex ()
{
import std.uni : isWhite, isNumber;

Expand Down
137 changes: 115 additions & 22 deletions tests/calc.at
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ class CalcLexer(R) : Lexer
return res;
}

int yylex ()
TokenKind yylex ()
{]AT_LOCATION_IF([[
location.begin = location.end;]])[

Expand Down Expand Up @@ -342,7 +342,20 @@ class CalcLexer(R) : Lexer
return TokenKind.YYerror;
}

return c;
switch (c)
{
case '+': return TokenKind.PLUS;
case '-': return TokenKind.MINUS;
case '*': return TokenKind.STAR;
case '/': return TokenKind.SLASH;
case '(': return TokenKind.LPAR;
case ')': return TokenKind.RPAR;
case '\n': return TokenKind.EOL;
case '=': return TokenKind.EQUAL;
case '^': return TokenKind.POW;
case '!': return TokenKind.NOT;
default: return TokenKind.YYUNDEF;
}
}
}
]])
Expand Down Expand Up @@ -444,13 +457,6 @@ m4_define([_AT_DATA_CALC_Y(c)],
[AT_DATA_GRAMMAR([calc.y],
[[/* Infix notation calculator--calc */
]$4[
]AT_LANG_MATCH(
[d], [[
%code imports {
alias semantic_value = int;
}
]],
[c\|c++], [[
%code requires
{
]AT_LOCATION_TYPE_SPAN_IF([[
Expand Down Expand Up @@ -489,7 +495,6 @@ void location_print (FILE *o, Span s);
/* Exercise pre-prologue dependency to %union. */
typedef int semantic_value;
}
]])[

/* Exercise %union. */
%union
Expand Down Expand Up @@ -592,9 +597,7 @@ exp:
char buf[1024];
snprintf (buf, sizeof buf, "error: %d != %d", $1, $3);
]AT_GLR_IF([[yyparser.]])[error (]AT_LOCATION_IF([[@$, ]])[buf);
}]],
[d], [[
yyerror (]AT_LOCATION_IF([[@$, ]])[format ("error: %d != %d", $1, $3));]])[
}]])[
$$ = $1;
}
| exp '+' exp { $$ = $1 + $3; }
Expand All @@ -617,18 +620,16 @@ exp:
[c++], [[
{
]AT_GLR_IF([[yyparser.]])[error (]AT_LOCATION_IF([[@3, ]])["error: null divisor");
}]],
[d], [[
yyerror (]AT_LOCATION_IF([[@3, ]])["error: null divisor");]])[
}]])[
else
$$ = $1 / $3;
}
| '-' exp %prec NEG { $$ = -$2; }
| exp '^' exp { $$ = power ($1, $3); }
| '(' exp ')' { $$ = $2; }
| '(' error ')' { $$ = 1111; ]AT_D_IF([], [yyerrok;])[ }
| '!' { $$ = 0; ]AT_D_IF([return YYERROR], [YYERROR])[; }
| '-' error { $$ = 0; ]AT_D_IF([return YYERROR], [YYERROR])[; }
| '(' error ')' { $$ = 1111; yyerrok; }
| '!' { $$ = 0; YYERROR; }
| '-' error { $$ = 0; YYERROR; }
;
%%

Expand Down Expand Up @@ -682,11 +683,100 @@ AT_DATA_SOURCE([[calc-main.]AT_LANG_EXT],

]AT_CALC_MAIN])
])
])# _AT_DATA_CALC_Y
])# _AT_DATA_CALC_Y(c)


m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(c++)])
m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(d)])

m4_define([_AT_DATA_CALC_Y(d)],
[AT_DATA_GRAMMAR([calc.y],
[[/* Infix notation calculator--calc */
]$4[
%code imports {
alias semantic_value = int;
}
/* Exercise %union. */
%union
{
semantic_value ival;
};
%printer { fprintf (yyo, "%d", $$); } <ival>;

/* Bison Declarations */
%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of input"])[
%token <ival> NUM "number"
%type <ival> exp

%token PLUS "+"
MINUS "-"
STAR "*"
SLASH "/"
LPAR "("
RPAR ")"
EQUAL "="
POW "^"
NOT "!"
EOL "\n"

%nonassoc "=" /* comparison */
%left "-" "+"
%left "*" "/"
%precedence NEG /* negation--unary minus */
%right "^" /* exponentiation */

/* Grammar follows */
%%
input:
line
| input line { ]AT_PARAM_IF([++*count; ++global_count;])[ }
;

line:
EOL
| exp EOL { ]AT_PARAM_IF([*result = global_result = $1;], [AT_D_IF([], [USE ($1);])])[ }
;

exp:
NUM
| exp "=" exp
{
if ($1 != $3)
yyerror (]AT_LOCATION_IF([[@$, ]])[format ("error: %d != %d", $1, $3));
$$ = $1;
}
| exp "+" exp { $$ = $1 + $3; }
| exp "-" exp { $$ = $1 - $3; }
| exp "*" exp { $$ = $1 * $3; }
| exp "/" exp
{
if ($3 == 0)
yyerror (]AT_LOCATION_IF([[@3, ]])["error: null divisor");
else
$$ = $1 / $3;
}
| "-" exp %prec NEG { $$ = -$2; }
| exp "^" exp { $$ = power ($1, $3); }
| "(" exp ")" { $$ = $2; }
| "(" error ")" { $$ = 1111; ]AT_D_IF([], [yyerrok;])[ }
| "!" { $$ = 0; return YYERROR; }
| "-" error { $$ = 0; return YYERROR; }
;
%%

int
power (int base, int exponent)
{
int res = 1;
assert (0 <= exponent);
for (/* Niente */; exponent; --exponent)
res *= base;
return res;
}

]AT_YYERROR_DEFINE[
]AT_CALC_YYLEX
AT_CALC_MAIN])
])# _AT_DATA_CALC_Y(d)

m4_define([_AT_DATA_CALC_Y(java)],
[AT_DATA_GRAMMAR([Calc.y],
Expand Down Expand Up @@ -883,7 +973,10 @@ AT_PERL_REQUIRE([[-pi -e 'use strict;
s{syntax error on token \[(.*?)\] \(expected: (.*)\)}
{
my $unexp = $][1;
my @exps = $][2 =~ /\[(.*?)\]/g;
my @exps = $][2 =~ /\[(.*?)\]/g;]AT_D_IF([[
# In the case of D, there are no single quotes around the symbols.
$unexp =~ s/'"'(.)'"'/$][1/g;
s/'"'(.)'"'/$][1/g for @exps;]])[
($][#exps && $][#exps < 4)
? "syntax error, unexpected $unexp, expecting @{[join(\" or \", @exps)]}"
: "syntax error, unexpected $unexp";
Expand Down
2 changes: 1 addition & 1 deletion tests/scanner.at
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class YYLexer(R) : Lexer
return semanticVal_;
}

int yylex ()
TokenKind yylex ()
{
import std.uni : isNumber;
// Handle EOF.
Expand Down

0 comments on commit f296669

Please sign in to comment.