examples: d: demonstrate location tracking

* examples/d/calc/calc.y: Track locations.
* examples/d/calc/calc.test: Check locations.
This commit is contained in:
Adela Vais
2020-09-03 08:42:06 +02:00
committed by Akim Demaille
parent 8032dde383
commit 6e1d83c8a8
3 changed files with 60 additions and 10 deletions

View File

@@ -9,7 +9,7 @@ afterwards.
The usual calculator. The usual calculator.
## d/calc.y ## d/calc.y
A richer implementation of the calculator. A richer implementation of the calculator, with location tracking.
<!--- <!---

View File

@@ -33,4 +33,19 @@ run 0 5
cat >input <<EOF cat >input <<EOF
1 + 2 * * 3 1 + 2 * * 3
EOF EOF
run 1 "err: syntax error, unexpected *, expecting + or - or ( or number" run 1 "err: 1.9: syntax error, unexpected *, expecting + or - or ( or number"
cat >input <<EOF
1111 + 1111 2222
EOF
run 1 "err: 1.13-16: syntax error, unexpected number"
cat >input <<EOF
1 +
EOF
run 1 "err: 1.4-2.0: syntax error, unexpected end of line, expecting + or - or ( or number"
cat >input <<EOF
99 009
EOF
run 1 "err: 1.4-6: syntax error, unexpected number"

View File

@@ -22,6 +22,8 @@
%define api.parser.class {Calc} %define api.parser.class {Calc}
%define parse.error verbose %define parse.error verbose
%locations
%union { %union {
int ival; int ival;
} }
@@ -94,13 +96,16 @@ class CalcLexer(R) : Lexer
this(R r) { input = r; } this(R r) { input = r; }
YYPosition start;
YYPosition end;
// 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;
public void yyerror (string s) void yyerror(YYLocation loc, string s)
{ {
exit_status = 1; exit_status = 1;
stderr.writeln (s); stderr.writeln(loc.toString(), ": ", s);
} }
YYSemanticType semanticVal_; YYSemanticType semanticVal_;
@@ -116,24 +121,39 @@ class CalcLexer(R) : Lexer
// Skip initial spaces // Skip initial spaces
while (!input.empty && input.front != '\n' && isWhite (input.front)) while (!input.empty && input.front != '\n' && isWhite (input.front))
{
start = end;
end.column++;
input.popFront; input.popFront;
}
if (input.empty) if (input.empty)
return TokenKind.YYEOF; return TokenKind.YYEOF;
// Numbers. // Numbers.
if (input.front.isNumber) 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)
{ {
import std.conv : parse; lenChars++;
semanticVal_.ival = input.parse!int; copy.popFront;
return TokenKind.NUM;
} }
start = end;
end.column += lenChars;
return TokenKind.NUM;
}
// Individual characters // Individual characters
auto ch = input.front; auto ch = input.front;
input.popFront; input.popFront;
start = end;
end.column++;
switch (ch) switch (ch)
{ {
case '=': return TokenKind.EQ; case '=': return TokenKind.EQ;
case '+': return TokenKind.PLUS; case '+': return TokenKind.PLUS;
case '-': return TokenKind.MINUS; case '-': return TokenKind.MINUS;
@@ -141,9 +161,24 @@ class CalcLexer(R) : Lexer
case '/': return TokenKind.SLASH; case '/': return TokenKind.SLASH;
case '(': return TokenKind.LPAR; case '(': return TokenKind.LPAR;
case ')': return TokenKind.RPAR; case ')': return TokenKind.RPAR;
case '\n': return TokenKind.EOL; case '\n':
default: assert(0); {
end.line++;
end.column = 1;
return TokenKind.EOL;
} }
default: assert(0);
}
}
YYPosition startPos() const
{
return start;
}
YYPosition endPos() const
{
return end;
} }
} }