d: modernize the scanner of the example

https://lists.gnu.org/archive/html/bison-patches/2019-02/msg00121.html

* examples/d/calc.y (CalcLexer): Stop shoehorning C's API into D: use
a range based approach in the scanner, rather than some imitation of
getc/ungetc.
(main): Adjust.
This commit is contained in:
H. S. Teoh
2019-03-01 06:16:54 +01:00
committed by Akim Demaille
parent 8eac78f8ef
commit f8408562f8

View File

@@ -53,54 +53,30 @@ exp:
; ;
%% %%
class CalcLexer : Lexer { import std.range.primitives;
auto calcLexer(R)(R range)
if (isInputRange!R && is (ElementType!R : dchar))
{
return new CalcLexer!R(range);
}
class CalcLexer(R) : Lexer
if (isInputRange!R && is (ElementType!R : dchar))
{
R input;
this(R r) { input = r; }
// Should be a local in main, shared with %parse-param. // Should be a local in main, shared with %parse-param.
int exit_status = 0; int exit_status = 0;
int
get_char ()
{
import stdc = core.stdc.stdio;
return stdc.getc (stdc.stdin);
}
void
unget_char (int c)
{
import stdc = core.stdc.stdio;
stdc.ungetc (c, stdc.stdin);
}
public void yyerror (string s) public void yyerror (string s)
{ {
exit_status = 1; exit_status = 1;
stderr.writeln (s); stderr.writeln (s);
} }
int
read_signed_integer ()
{
int c = get_char ();
int sign = 1;
int n = 0;
if (c == '-')
{
c = get_char ();
sign = -1;
}
while (isDigit (c))
{
n = 10 * n + (c - '0');
c = get_char ();
}
unget_char (c);
return sign * n;
}
YYSemanticType semanticVal_; YYSemanticType semanticVal_;
public final @property YYSemanticType semanticVal () public final @property YYSemanticType semanticVal ()
@@ -110,21 +86,30 @@ class CalcLexer : Lexer {
int yylex () int yylex ()
{ {
int c; import std.uni : isWhite, isNumber;
/* Skip white spaces. */
do
{}
while ((c = get_char ()) == ' ' || c == '\t');
/* process numbers */ // Skip initial spaces
if (c == '.' || isDigit (c)) while (!input.empty && input.front != '\n' && isWhite (input.front))
{ {
unget_char (c); input.popFront;
semanticVal_.ival = read_signed_integer (); }
// Handle EOF.
if (input.empty)
return YYTokenType.EOF;
// Numbers.
if (input.front == '.' || input.front.isNumber)
{
import std.conv : parse;
semanticVal_.ival = input.parse!int;
return YYTokenType.NUM; return YYTokenType.NUM;
} }
switch (c) // Individual characters
auto ch = input.front;
input.popFront;
switch (ch)
{ {
case EOF: return YYTokenType.EOF; case EOF: return YYTokenType.EOF;
case '=': return YYTokenType.EQ; case '=': return YYTokenType.EQ;
@@ -142,7 +127,16 @@ class CalcLexer : Lexer {
int main () int main ()
{ {
CalcLexer l = new CalcLexer (); import std.algorithm : map, joiner;
import std.stdio;
import std.utf : byDchar;
auto l = stdin
.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;
Calc p = new Calc (l); Calc p = new Calc (l);
p.parse (); p.parse ();
return l.exit_status; return l.exit_status;