Files
bison/examples/d/calc/calc.y
Adela Vais e5854bbddd d: change YYLocation's type from class to struct
This avoids heap allocation and gives minimal costs for the
creation and destruction of the YYParser.Symbol struct if
the location tracking is active.

Suggested by H. S. Teoh.

* data/skeletons/lalr1.d: Here.
* doc/bison.texi: Document it.
* examples/d/calc/calc.y: Adjust.
* tests/calc.at: Test it.
2020-11-20 22:09:31 +01:00

190 lines
4.4 KiB
Plaintext

/* Parser and scanner for calc in D. -*- D -*-
Copyright (C) 2018-2020 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
%language "D"
%define api.parser.class {Calc}
%define parse.error verbose
%locations
%union {
int ival;
}
/* Bison Declarations */
%token PLUS "+"
MINUS "-"
STAR "*"
SLASH "/"
LPAR "("
RPAR ")"
EOL "end of line"
%token <ival> NUM "number"
%type <ival> exp
%left "-" "+"
%left "*" "/"
%precedence UNARY /* unary operators */
/* Grammar follows */
%%
input:
line
| input line
;
line:
EOL
| exp EOL { writeln ($exp); }
| error EOL { yyerrok(); }
;
exp:
NUM { $$ = $1; }
| exp "+" exp { $$ = $1 + $3; }
| exp "-" exp { $$ = $1 - $3; }
| exp "*" exp { $$ = $1 * $3; }
| exp "/" exp { $$ = $1 / $3; }
| "+" exp %prec UNARY { $$ = $2; }
| "-" exp %prec UNARY { $$ = -$2; }
| "(" exp ")" { $$ = $2; }
;
%%
import std.range.primitives;
import std.stdio;
auto calcLexer(R)(R range)
if (isInputRange!R && is(ElementType!R : dchar))
{
return new CalcLexer!R(range);
}
auto calcLexer(File f)
{
import std.algorithm : map, joiner;
import std.utf : byDchar;
return f.byChunk(1024) // avoid making a syscall roundtrip per char
.map!(chunk => cast(char[]) chunk) // because byChunk returns ubyte[]
.joiner // combine chunks into a single virtual range of char
.calcLexer; // forward to other overload
}
class CalcLexer(R) : Lexer
if (isInputRange!R && is(ElementType!R : dchar))
{
R input;
this(R r) { input = r; }
YYPosition start;
YYPosition end;
// Should be a local in main, shared with %parse-param.
int exit_status = 0;
void yyerror(const YYLocation loc, string s)
{
exit_status = 1;
stderr.writeln(loc.toString(), ": ", s);
}
YYSemanticType semanticVal_;
public final YYSemanticType semanticVal()
{
return semanticVal_;
}
Calc.Symbol yylex()
{
import std.uni : isWhite, isNumber;
// Skip initial spaces
while (!input.empty && input.front != '\n' && isWhite(input.front))
{
start = end;
end.column++;
input.popFront;
}
if (input.empty)
return Calc.Symbol(TokenKind.YYEOF, YYLocation(startPos, endPos));
// Numbers.
if (input.front.isNumber)
{
int lenChars = 0;
auto copy = input;
import std.conv : parse;
semanticVal_.ival = input.parse!int;
while (!input.empty && copy.front != input.front)
{
lenChars++;
copy.popFront;
}
start = end;
end.column += lenChars;
return Calc.Symbol(TokenKind.NUM, semanticVal_.ival, YYLocation(startPos, endPos));
}
// Individual characters
auto ch = input.front;
input.popFront;
start = end;
end.column++;
switch (ch)
{
case '+': return Calc.Symbol(TokenKind.PLUS, YYLocation(startPos, endPos));
case '-': return Calc.Symbol(TokenKind.MINUS, YYLocation(startPos, endPos));
case '*': return Calc.Symbol(TokenKind.STAR, YYLocation(startPos, endPos));
case '/': return Calc.Symbol(TokenKind.SLASH, YYLocation(startPos, endPos));
case '(': return Calc.Symbol(TokenKind.LPAR, YYLocation(startPos, endPos));
case ')': return Calc.Symbol(TokenKind.RPAR, YYLocation(startPos, endPos));
case '\n':
{
end.line++;
end.column = 1;
return Calc.Symbol(TokenKind.EOL, YYLocation(startPos, endPos));
}
default: assert(0);
}
}
YYPosition startPos() const
{
return start;
}
YYPosition endPos() const
{
return end;
}
}
int main()
{
auto l = calcLexer(stdin);
auto p = new Calc(l);
p.parse();
return l.exit_status;
}