summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorAkim Demaille <akim.demaille@gmail.com>2018-12-09 14:19:00 +0100
committerAkim Demaille <akim.demaille@gmail.com>2018-12-09 15:30:25 +0100
commitd657da9fb40e961401069c3767bb12902c2faec1 (patch)
treef542fc74fb5917d1ce817c11576b2f8495921eb7 /examples
parent4cbdcaa5729826953681ab2959c1ec963c63bc12 (diff)
downloadbison-d657da9fb40e961401069c3767bb12902c2faec1.tar.gz
examples: add a simple Flex+Bison example in C
Suggested by Askar Safin. http://lists.gnu.org/archive/html/bug-bison/2018-12/msg00003.html * examples/c/lexcalc/Makefile, examples/c/lexcalc/README.md, * examples/c/lexcalc/lexcalc.test, examples/c/lexcalc/local.mk, * examples/c/lexcalc/parse.y, examples/c/lexcalc/scan.l: New.
Diffstat (limited to 'examples')
-rw-r--r--examples/c++/calc++/README.md11
-rw-r--r--examples/c/lexcalc/Makefile34
-rw-r--r--examples/c/lexcalc/README.md28
-rw-r--r--examples/c/lexcalc/lexcalc.test27
-rw-r--r--examples/c/lexcalc/local.mk32
-rw-r--r--examples/c/lexcalc/parse.y95
-rw-r--r--examples/c/lexcalc/scan.l43
-rw-r--r--examples/c/local.mk1
-rw-r--r--examples/c/rpcalc/Makefile2
9 files changed, 268 insertions, 5 deletions
diff --git a/examples/c++/calc++/README.md b/examples/c++/calc++/README.md
index d4d5154f..02e0d681 100644
--- a/examples/c++/calc++/README.md
+++ b/examples/c++/calc++/README.md
@@ -1,6 +1,10 @@
-This directory contains calc++, a simple Bison grammar file in C++.
+# calc++ - A Flex+Bison calculator
-Please, read the corresponding chapter in the documentation: "A Complete C++
+This directory contains calc++, a Bison grammar file in C++. If you never
+saw the traditional implementation in C, please first read
+examples/c/lexcalc, which can be seen as a C precursor of this example.
+
+Read the corresponding chapter in the documentation: "A Complete C++
Example". It is also available on line (maybe with a different version of
Bison):
https://www.gnu.org/software/bison/manual/html_node/A-Complete-C_002b_002b-Example.html
@@ -27,7 +31,6 @@ You may pass `-p` to activate the parser debug traces, and `-s` to activate
the scanner's.
<!---
-
Local Variables:
fill-column: 76
ispell-dictionary: "american"
@@ -50,5 +53,5 @@ 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/>.
-# LocalWords: mfcalc calc parsers yy MERCHANTABILITY Ctrl ispell american
+# LocalWords: calc parsers yy MERCHANTABILITY Ctrl ispell american
--->
diff --git a/examples/c/lexcalc/Makefile b/examples/c/lexcalc/Makefile
new file mode 100644
index 00000000..e7c798cd
--- /dev/null
+++ b/examples/c/lexcalc/Makefile
@@ -0,0 +1,34 @@
+# This Makefile is designed to be simple and readable. It does not
+# aim at portability. It requires GNU Make.
+
+BASE = lexcalc
+BISON = bison
+FLEX = flex
+XSLTPROC = xsltproc
+
+all: $(BASE)
+
+%.c %.h %.xml %.gv: %.y
+ $(BISON) $(BISONFLAGS) --defines --xml --graph=$*.gv -o $*.c $<
+
+%.c: %.l
+ $(FLEX) $(FLEXFLAGS) -o$@ $<
+
+scan.o: parse.h
+lexcalc: parse.o scan.o
+ $(CC) $(CFLAGS) -o $@ $^
+
+run: $(BASE)
+ @echo "Type arithmetic expressions. Quit with ctrl-d."
+ ./$<
+
+html: parse.html
+%.html: %.xml
+ $(XSLTPROC) $(XSLTPROCFLAGS) -o $@ $$($(BISON) --print-datadir)/xslt/xml2xhtml.xsl $<
+
+CLEANFILES = \
+ $(BASE) *.o \
+ parse.[ch] parse.output parse.xml parse.html parse.gv \
+ scan.c
+clean:
+ rm -f $(CLEANFILES)
diff --git a/examples/c/lexcalc/README.md b/examples/c/lexcalc/README.md
new file mode 100644
index 00000000..32e6d534
--- /dev/null
+++ b/examples/c/lexcalc/README.md
@@ -0,0 +1,28 @@
+# lexcalc - calculator with Flex and Bison
+
+This directory contains lexcalc, the traditional example of using Flex and
+Bison to build a simple calculator.
+
+<!---
+Local Variables:
+fill-column: 76
+ispell-dictionary: "american"
+End:
+
+Copyright (C) 2018 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/>.
+--->
diff --git a/examples/c/lexcalc/lexcalc.test b/examples/c/lexcalc/lexcalc.test
new file mode 100644
index 00000000..0df4e38c
--- /dev/null
+++ b/examples/c/lexcalc/lexcalc.test
@@ -0,0 +1,27 @@
+#! /bin/sh
+
+# Copyright (C) 2018 Free Software Foundation, Inc.
+#
+# 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/>.
+
+cat >input <<EOF
+1+2*3
+EOF
+run 0 7
+
+cat >input <<EOF
+(1+2) * 3
+EOF
+run 0 9
+run -noerr 0 9 -p
diff --git a/examples/c/lexcalc/local.mk b/examples/c/lexcalc/local.mk
new file mode 100644
index 00000000..69d87d31
--- /dev/null
+++ b/examples/c/lexcalc/local.mk
@@ -0,0 +1,32 @@
+## Copyright (C) 2018 Free Software Foundation, Inc.
+##
+## 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/>.
+
+lexcalcdir = $(docdir)/%D%
+
+## ------ ##
+## Calc. ##
+## ------ ##
+
+check_PROGRAMS += %D%/lexcalc
+TESTS += %D%/lexcalc.test
+EXTRA_DIST += %D%/lexcalc.test
+%C%_lexcalc_SOURCES = %D%/parse.y %D%/parse.h %D%/scan.l
+
+# Don't use gnulib's system headers.
+%C%_lexcalc_CPPFLAGS = -I$(top_srcdir)/%D% -I$(top_builddir)/%D%
+
+dist_lexcalc_DATA = %D%/parse.y %D%/scan.l %D%/Makefile %D%/README.md
+CLEANFILES += %D%/lexcalc %D%/*.o %D%/parse.c %D%/scan.c
+CLEANDIRS += %D%/*.dSYM
diff --git a/examples/c/lexcalc/parse.y b/examples/c/lexcalc/parse.y
new file mode 100644
index 00000000..5306de30
--- /dev/null
+++ b/examples/c/lexcalc/parse.y
@@ -0,0 +1,95 @@
+// Prologue (directives).
+%expect 0
+
+// Emitted in the header file, after the definition of YYSTYPE.
+%code provides
+{
+ // Tell Flex the expected prototype of yylex.
+#define YY_DECL \
+ enum yytokentype yylex (YYSTYPE* yylval, int *nerrs)
+ YY_DECL;
+
+ void yyerror (int *nerrs, const char *msg);
+}
+
+// Emitted on top of the implementation file.
+%code top
+{
+#include <stdio.h> /* printf. */
+#include <stdlib.h> /* getenv. */
+}
+
+%define api.pure full
+%define api.token.prefix {TOK_}
+%define api.value.type union
+%define parse.error verbose
+%define parse.trace
+ // Error count, exchanged between main, yyparse and yylex.
+%param {int *nerrs}
+
+%token
+ PLUS "+"
+ MINUS "-"
+ STAR "*"
+ SLASH "/"
+ LPAREN "("
+ RPAREN ")"
+ EOL "end-of-line"
+ EOF 0 "end-of-file"
+;
+
+%token <int> NUM "number"
+%type <int> exp line
+%printer { fprintf (yyo, "%d", $$); } <int>
+
+// Precedence (from lowest to highest) and associativity.
+%left "+" "-"
+%left "*" "/"
+
+%%
+// Rules.
+input:
+ %empty
+| input line { printf ("%d\n", $line); }
+;
+
+line:
+ exp EOL { $$ = $1; }
+| error EOL { yyerrok; }
+;
+
+exp:
+ exp "+" exp { $$ = $1 + $3; }
+| exp "-" exp { $$ = $1 - $3; }
+| exp "*" exp { $$ = $1 * $3; }
+| exp "/" exp
+ {
+ if ($3 == 0)
+ {
+ yyerror (nerrs, "invalid division by zero");
+ YYERROR;
+ }
+ else
+ $$ = $1 / $3;
+ }
+| "(" exp ")" { $$ = $2; }
+| NUM { $$ = $1; }
+;
+%%
+// Epilogue (C code).
+void yyerror(int *nerrs, const char *msg)
+{
+ fprintf (stderr, "%s\n", msg);
+ ++nerrs;
+}
+
+int main (void)
+{
+ int nerrs = 0;
+ // Enable parser runtime debugging.
+ if (!!getenv ("YYDEBUG"))
+ yydebug = 1;
+ yyparse (&nerrs);
+ // Exit on failure if there were errors.
+ return !!nerrs;
+}
diff --git a/examples/c/lexcalc/scan.l b/examples/c/lexcalc/scan.l
new file mode 100644
index 00000000..fc73f3b0
--- /dev/null
+++ b/examples/c/lexcalc/scan.l
@@ -0,0 +1,43 @@
+/* Prologue (directives). -*- C++ -*- */
+
+/* Disable Flex features we don't need, to avoid warnings. */
+%option nodefault noinput nounput noyywrap
+
+%{
+#include <limits.h> /* INT_MIN */
+#include <stdlib.h> /* strtol */
+
+#include "parse.h"
+%}
+
+%%
+ /* Rules. */
+
+"+" return TOK_PLUS;
+"-" return TOK_MINUS;
+"*" return TOK_STAR;
+"/" return TOK_SLASH;
+
+"(" return TOK_LPAREN;
+")" return TOK_RPAREN;
+
+ /* Scan an integer. */
+[0-9]+ {
+ errno = 0;
+ long n = strtol (yytext, NULL, 10);
+ if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
+ yyerror (nerrs, "integer is out of range");
+ yylval->TOK_NUM = (int) n;
+ return TOK_NUM;
+}
+
+ /* Ignore white spaces. */
+[ \t]+ continue;
+
+"\n" return TOK_EOL;
+
+. yyerror (nerrs, "syntax error, invalid character");
+
+<<EOF>> return TOK_EOF;
+%%
+/* Epilogue (C code). */
diff --git a/examples/c/local.mk b/examples/c/local.mk
index dcd90424..fb1c33d1 100644
--- a/examples/c/local.mk
+++ b/examples/c/local.mk
@@ -16,5 +16,6 @@
cdir = $(docdir)/%D%
dist_c_DATA = %D%/README.md
+include %D%/lexcalc/local.mk
include %D%/mfcalc/local.mk
include %D%/rpcalc/local.mk
diff --git a/examples/c/rpcalc/Makefile b/examples/c/rpcalc/Makefile
index 87e18f34..624f247b 100644
--- a/examples/c/rpcalc/Makefile
+++ b/examples/c/rpcalc/Makefile
@@ -14,7 +14,7 @@ all: $(BASE)
$(CC) $(CFLAGS) -o $@ $<
run: $(BASE)
- @echo "Type arithmetic expressions in reverse polish notation. Quit with ctrl-d."
+ @echo "Type arithmetic expressions in Reverse Polish Notation. Quit with ctrl-d."
./$<
html: $(BASE).html