[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 1/6] examples: lexcalc: demonstrate location tracking
From: |
Akim Demaille |
Subject: |
[PATCH 1/6] examples: lexcalc: demonstrate location tracking |
Date: |
Sun, 1 Mar 2020 12:30:59 +0100 |
The bistromathic example should not use Flex, it makes it too complex.
But it was the only example to show location tracking with Flex.
* examples/c/lexcalc/lexcalc.test, examples/c/lexcalc/parse.y,
* examples/c/lexcalc/scan.l: Demonstrate location tracking as is done
in bistromathic.
---
NEWS | 3 +++
examples/c/README.md | 5 +++--
examples/c/bistromathic/README.md | 2 +-
examples/c/bistromathic/parse.y | 4 ++--
examples/c/lexcalc/README.md | 2 ++
examples/c/lexcalc/lexcalc.test | 7 ++++++-
examples/c/lexcalc/parse.y | 14 +++++++++-----
examples/c/lexcalc/scan.l | 25 ++++++++++++++++++++-----
8 files changed, 46 insertions(+), 16 deletions(-)
diff --git a/NEWS b/NEWS
index 0daa3048..b94ccaf0 100644
--- a/NEWS
+++ b/NEWS
@@ -101,6 +101,9 @@ GNU Bison NEWS
There are now two examples in examples/java: a very simple calculator, and
one that tracks locations to provide acurate error messages.
+ The lexcalc example (a simple example in C based on Flex and Bison) now
+ also demonstrates location tracking.
+
A new C example, bistromathic, is a fully featured calculator using many
Bison features: pure interface, location tracking, internationalized
custom error messages, lookahead-correction, rich debug traces, etc.
diff --git a/examples/c/README.md b/examples/c/README.md
index 893dfe2f..1a98d462 100644
--- a/examples/c/README.md
+++ b/examples/c/README.md
@@ -28,7 +28,8 @@ Extracted from the documentation: "Multi-Function Calculator:
mfcalc".
https://www.gnu.org/software/bison/manual/html_node/Multi_002dfunction-Calc.html
## lexcalc - calculator with Flex and Bison
-The calculator, redux. This time using a scanner generated by Flex.
+The calculator with precedence directives and location tracking. It uses
+Flex to generate the scanner.
## reccalc - recursive calculator with Flex and Bison
The example builds on top of the previous one to provide a reentrant parser.
@@ -53,7 +54,7 @@ This example demonstrates the best practices when using Bison.
- Its interface is pure.
- It uses a custom syntax error with location tracking, lookahead correction
and token internationalization.
-- It enables debug trace support with formatting of semantic values.
+- It supports debug traces with semantic values.
- It uses named references instead of the traditional $1, $2, etc.
It also uses Flex to generate the scanner.
diff --git a/examples/c/bistromathic/README.md
b/examples/c/bistromathic/README.md
index 25411867..9f672d14 100644
--- a/examples/c/bistromathic/README.md
+++ b/examples/c/bistromathic/README.md
@@ -3,7 +3,7 @@ This example demonstrates the best practices when using Bison.
- Its interface is pure.
- It uses a custom syntax error with location tracking, lookahead correction
and token internationalization.
-- It enables debug trace support with formatting of semantic values.
+- It supports debug traces with semantic values.
- It uses named references instead of the traditional $1, $2, etc.
It also uses Flex to generate the scanner.
diff --git a/examples/c/bistromathic/parse.y b/examples/c/bistromathic/parse.y
index 373bc074..9698161f 100644
--- a/examples/c/bistromathic/parse.y
+++ b/examples/c/bistromathic/parse.y
@@ -209,10 +209,10 @@ yyreport_syntax_error (const yyparse_context_t *ctx)
}
// Called by yyparse on error.
-void yyerror (YYLTYPE *loc, char const *s)
+void yyerror (YYLTYPE *loc, char const *msg)
{
YY_LOCATION_PRINT (stderr, *loc);
- fprintf (stderr, ": %s\n", s);
+ fprintf (stderr, ": %s\n", msg);
}
int main (int argc, char const* argv[])
diff --git a/examples/c/lexcalc/README.md b/examples/c/lexcalc/README.md
index ddf693c4..58d9d9aa 100644
--- a/examples/c/lexcalc/README.md
+++ b/examples/c/lexcalc/README.md
@@ -3,6 +3,8 @@
This directory contains lexcalc, the traditional example of using Flex and
Bison to build a simple calculator.
+It features detailed syntax errors with locations.
+
<!---
Local Variables:
fill-column: 76
diff --git a/examples/c/lexcalc/lexcalc.test b/examples/c/lexcalc/lexcalc.test
index cfc5d83f..c9eb62f1 100644
--- a/examples/c/lexcalc/lexcalc.test
+++ b/examples/c/lexcalc/lexcalc.test
@@ -29,4 +29,9 @@ run -noerr 0 9 -p
cat >input <<EOF
(1+2) *
EOF
-run 1 'err: syntax error, unexpected end-of-line, expecting ( or number'
+run 1 'err: 1.8-2.0: syntax error, unexpected end-of-line, expecting ( or
number'
+
+cat >input <<EOF
+1 / (2 - 2)
+EOF
+run 1 'err: 1.1-11: error: division by zero"
diff --git a/examples/c/lexcalc/parse.y b/examples/c/lexcalc/parse.y
index 060af4ab..62201a16 100644
--- a/examples/c/lexcalc/parse.y
+++ b/examples/c/lexcalc/parse.y
@@ -6,10 +6,10 @@
{
// Tell Flex the expected prototype of yylex.
#define YY_DECL \
- enum yytokentype yylex (YYSTYPE* yylval, int *nerrs)
+ enum yytokentype yylex (YYSTYPE* yylval, YYLTYPE *yylloc, int *nerrs)
YY_DECL;
- void yyerror (int *nerrs, const char *msg);
+ void yyerror (YYLTYPE *loc, int *nerrs, const char *msg);
}
// Emitted on top of the implementation file.
@@ -33,6 +33,9 @@
// Generate detailed error messages.
%define parse.error detailed
+// with locations.
+%locations
+
// Enable debug traces (see yydebug in main).
%define parse.trace
@@ -78,7 +81,7 @@ exp:
{
if ($3 == 0)
{
- yyerror (nerrs, "invalid division by zero");
+ yyerror (&@$, nerrs, "error: division by zero");
YYERROR;
}
else
@@ -90,9 +93,10 @@ exp:
%%
// Epilogue (C code).
-void yyerror (int *nerrs, const char *msg)
+void yyerror (YYLTYPE *loc, int *nerrs, const char *msg)
{
- fprintf (stderr, "%s\n", msg);
+ YY_LOCATION_PRINT (stderr, *loc);
+ fprintf (stderr, ": %s\n", msg);
++*nerrs;
}
diff --git a/examples/c/lexcalc/scan.l b/examples/c/lexcalc/scan.l
index e0b68504..8be67cae 100644
--- a/examples/c/lexcalc/scan.l
+++ b/examples/c/lexcalc/scan.l
@@ -9,9 +9,24 @@
#include <stdlib.h> /* strtol */
#include "parse.h"
+
+ // Each time a rule is matched, advance the end cursor/position.
+#define YY_USER_ACTION \
+ yylloc->last_column += yyleng;
+
+ // Move the first position onto the last.
+#define LOCATION_STEP() \
+ do { \
+ yylloc->first_line = yylloc->last_line; \
+ yylloc->first_column = yylloc->last_column; \
+ } while (0)
%}
%%
+%{
+ // Each time yylex is called, move the head position to the end one.
+ LOCATION_STEP ();
+%}
/* Rules. */
"+" return TOK_PLUS;
@@ -27,17 +42,17 @@
errno = 0;
long n = strtol (yytext, NULL, 10);
if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
- yyerror (nerrs, "integer is out of range");
+ yyerror (yylloc, nerrs, "integer is out of range");
yylval->TOK_NUM = (int) n;
return TOK_NUM;
}
- /* Ignore white spaces. */
-[ \t]+ continue;
+"\n" yylloc->last_line++; yylloc->last_column = 1; return TOK_EOL;
-"\n" return TOK_EOL;
+ /* Ignore white spaces. */
+[ \t]+ LOCATION_STEP (); continue;
-. yyerror (nerrs, "syntax error, invalid character");
+. yyerror (yylloc, nerrs, "syntax error, invalid character"); continue;
<<EOF>> return TOK_EOF;
%%
--
2.25.1
- [PATCH 0/6] RFC: examples: demonstrate yyexpected_tokens, Akim Demaille, 2020/03/01
- [PATCH 2/6] examples: bistromathic: strengthen tests, Akim Demaille, 2020/03/01
- [PATCH 1/6] examples: lexcalc: demonstrate location tracking,
Akim Demaille <=
- [PATCH 4/6] gnulib: use readline, Akim Demaille, 2020/03/01
- [PATCH 3/6] examples: bistromathic: don't use Flex, Akim Demaille, 2020/03/01
- [PATCH 6/6] examples: bistromathic: demonstrate use of yyexpected_tokens, Akim Demaille, 2020/03/01
- [PATCH 5/6] examples: use consistently the GFDL header for readmes, Akim Demaille, 2020/03/01