diff options
author | Akim Demaille <akim.demaille@gmail.com> | 2018-12-09 14:19:00 +0100 |
---|---|---|
committer | Akim Demaille <akim.demaille@gmail.com> | 2018-12-09 15:30:25 +0100 |
commit | d657da9fb40e961401069c3767bb12902c2faec1 (patch) | |
tree | f542fc74fb5917d1ce817c11576b2f8495921eb7 /examples | |
parent | 4cbdcaa5729826953681ab2959c1ec963c63bc12 (diff) | |
download | bison-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.md | 11 | ||||
-rw-r--r-- | examples/c/lexcalc/Makefile | 34 | ||||
-rw-r--r-- | examples/c/lexcalc/README.md | 28 | ||||
-rw-r--r-- | examples/c/lexcalc/lexcalc.test | 27 | ||||
-rw-r--r-- | examples/c/lexcalc/local.mk | 32 | ||||
-rw-r--r-- | examples/c/lexcalc/parse.y | 95 | ||||
-rw-r--r-- | examples/c/lexcalc/scan.l | 43 | ||||
-rw-r--r-- | examples/c/local.mk | 1 | ||||
-rw-r--r-- | examples/c/rpcalc/Makefile | 2 |
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 |