[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 3/6] examples: bistromathic: don't use Flex
From: |
Akim Demaille |
Subject: |
[PATCH 3/6] examples: bistromathic: don't use Flex |
Date: |
Sun, 1 Mar 2020 12:31:01 +0100 |
This example will soon use GNU readline, so its scanner should be easy
to use (concurrently) on strings, not streams. This is not a place
where Flex shines, and anyway, these are examples of Bison, not Flex.
There's already lexcalc and reccalc that demonstrate the use of Flex.
* examples/c/bistromathic/scan.l: Remove.
* examples/c/bistromathic/parse.y (yylex): New.
Adjust dependencies.
---
examples/c/README.md | 7 ++-
examples/c/bistromathic/README.md | 7 ++-
examples/c/bistromathic/local.mk | 22 ++++----
examples/c/bistromathic/parse.y | 88 +++++++++++++++++++++++++++++--
examples/c/bistromathic/scan.l | 67 -----------------------
5 files changed, 100 insertions(+), 91 deletions(-)
delete mode 100644 examples/c/bistromathic/scan.l
diff --git a/examples/c/README.md b/examples/c/README.md
index 1a98d462..95e2bb2a 100644
--- a/examples/c/README.md
+++ b/examples/c/README.md
@@ -52,13 +52,12 @@ push-parser model.
## bistromathic - all the bells and whistles
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.
+- Its hand-written scanner tracks locations.
+- It uses a custom syntax error with location, lookahead correction and
+ token internationalization.
- 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.
-
<!---
Local Variables:
diff --git a/examples/c/bistromathic/README.md
b/examples/c/bistromathic/README.md
index 9f672d14..8bef5136 100644
--- a/examples/c/bistromathic/README.md
+++ b/examples/c/bistromathic/README.md
@@ -1,13 +1,12 @@
# bistromathic - all the bells and whistles
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.
+- Its hand-written scanner tracks locations.
+- It uses a custom syntax error with location, lookahead correction and
+ token internationalization.
- 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.
-
<!---
Local Variables:
fill-column: 76
diff --git a/examples/c/bistromathic/local.mk b/examples/c/bistromathic/local.mk
index 78f2c937..0a805f9d 100644
--- a/examples/c/bistromathic/local.mk
+++ b/examples/c/bistromathic/local.mk
@@ -19,18 +19,16 @@ bistromathicdir = $(docdir)/%D%
## Bistromathics. ##
## --------------- ##
-if FLEX_WORKS
- check_PROGRAMS += %D%/bistromathic
- TESTS += %D%/bistromathic.test
- EXTRA_DIST += %D%/bistromathic.test
- nodist_%C%_bistromathic_SOURCES = %D%/parse.y %D%/parse.h %D%/scan.l
- %D%/calc.c: $(dependencies)
+check_PROGRAMS += %D%/bistromathic
+TESTS += %D%/bistromathic.test
+EXTRA_DIST += %D%/bistromathic.test
+nodist_%C%_bistromathic_SOURCES = %D%/parse.y %D%/parse.h
+%D%/calc.c: $(dependencies)
- # Don't use gnulib's system headers.
- %C%_bistromathic_CPPFLAGS = -I$(top_srcdir)/%D% -I$(top_builddir)/%D%
- %C%_bistromathic_LDADD = -lm
-endif FLEX_WORKS
+# Don't use gnulib's system headers.
+%C%_bistromathic_CPPFLAGS = -I$(top_srcdir)/%D% -I$(top_builddir)/%D%
+%C%_bistromathic_LDADD = -lm
-dist_bistromathic_DATA = %D%/parse.y %D%/scan.l %D%/Makefile %D%/README.md
-CLEANFILES += %D%/parse.[ch] %D%/scan.c %D%/parse.output
+dist_bistromathic_DATA = %D%/parse.y %D%/Makefile %D%/README.md
+CLEANFILES += %D%/parse.[ch] %D%/parse.output
CLEANDIRS += %D%/*.dSYM
diff --git a/examples/c/bistromathic/parse.y b/examples/c/bistromathic/parse.y
index 709651c2..39244f95 100644
--- a/examples/c/bistromathic/parse.y
+++ b/examples/c/bistromathic/parse.y
@@ -31,10 +31,7 @@
}
%code provides {
- #define YY_DECL \
- int yylex (YYSTYPE *yylval, YYLTYPE *yylloc)
- YY_DECL;
-
+ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc);
void yyerror (YYLTYPE *yylloc, char const *);
}
@@ -137,6 +134,10 @@ exp:
// End of grammar.
%%
+/*------------.
+| Functions. |
+`------------*/
+
struct init
{
char const *name;
@@ -189,6 +190,80 @@ getsym (char const *name)
return NULL;
}
+
+/*----------.
+| Scanner. |
+`----------*/
+
+int
+yylex (YYSTYPE *yylval, YYLTYPE *yylloc)
+{
+ int c;
+
+ // Ignore white space, get first nonwhite character.
+ do {
+ // Move the first position onto the last.
+ yylloc->first_line = yylloc->last_line;
+ yylloc->first_column = yylloc->last_column;
+
+ yylloc->last_column += 1;
+ c = getchar ();
+ } while (c == ' ' || c == '\t');
+
+ switch (c)
+ {
+ case '+': return TOK_PLUS;
+ case '-': return TOK_MINUS;
+ case '*': return TOK_STAR;
+ case '/': return TOK_SLASH;
+ case '^': return TOK_CARET;
+ case '=': return TOK_EQUAL;
+ case '(': return TOK_LPAREN;
+ case ')': return TOK_RPAREN;
+
+ case '\n':
+ yylloc->last_column = 1;
+ yylloc->last_line += 1;
+ return TOK_EOL;
+
+ case EOF: return TOK_EOF;
+
+ // Any other character is a token by itself.
+ default:
+ if (c == '.' || isdigit (c))
+ {
+ ungetc (c, stdin);
+ int nchars = 0;
+ scanf ("%lf%n", &yylval->TOK_NUM, &nchars);
+ yylloc->last_column += nchars - 1;
+ return TOK_NUM;
+ }
+ else if (islower (c))
+ {
+ ungetc (c, stdin);
+ int nchars = 0;
+ char buf[100];
+ scanf ("%99[a-z]%n", buf, &nchars);
+ symrec *s = getsym (buf);
+ if (!s)
+ s = putsym (buf, TOK_VAR);
+ yylval->TOK_VAR = s;
+ yylloc->last_column += nchars - 1;
+ return s->type;
+ }
+ else
+ {
+ yyerror (yylloc, "error: invalid character");
+ return yylex (yylval, yylloc);
+ }
+ }
+}
+
+
+/*---------.
+| Parser. |
+`---------*/
+
int
yyreport_syntax_error (const yyparse_context_t *ctx)
{
@@ -215,6 +290,11 @@ void yyerror (YYLTYPE *loc, char const *msg)
fprintf (stderr, ": %s\n", msg);
}
+
+/*-------.
+| Main. |
+`-------*/
+
int main (int argc, char const* argv[])
{
// Enable parse traces on option -p.
diff --git a/examples/c/bistromathic/scan.l b/examples/c/bistromathic/scan.l
deleted file mode 100644
index a0f60be5..00000000
--- a/examples/c/bistromathic/scan.l
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Prologue (directives). -*- C -*- */
-
-/* Disable Flex features we don't need, to avoid warnings. */
-%option nodefault noinput nounput noyywrap
-
-%{
-#include <errno.h> /* errno, ERANGE */
-#include <limits.h> /* INT_MIN */
-#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;
-"-" return TOK_MINUS;
-"*" return TOK_STAR;
-"/" return TOK_SLASH;
-"^" return TOK_CARET;
-
-"(" return TOK_LPAREN;
-")" return TOK_RPAREN;
-
-"=" return TOK_EQUAL;
-
- /* Scan an identifier. */
-[a-z]+ {
- symrec *s = getsym (yytext);
- if (!s)
- s = putsym (yytext, TOK_VAR);
- yylval->TOK_VAR = s;
- return s->type;
-}
-
- /* Scan a double precision number. */
-[0-9]+(\.[0-9]*)?|(\.[0-9]+) {
- sscanf (yytext, "%lf", &yylval->TOK_NUM);
- return TOK_NUM;
-}
-
-"\n" yylloc->last_line++; yylloc->last_column = 1; return TOK_EOL;
-
- /* Ignore white spaces. */
-[ \t]+ LOCATION_STEP (); continue;
-
-<<EOF>> return TOK_EOF;
-
-. yyerror (yylloc, "error: invalid character");
-%%
-/* Epilogue (C code). */
--
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, 2020/03/01
- [PATCH 4/6] gnulib: use readline, Akim Demaille, 2020/03/01
- [PATCH 3/6] examples: bistromathic: don't use Flex,
Akim Demaille <=
- [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