mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 04:13:03 +00:00
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.
This commit is contained in:
3
NEWS
3
NEWS
@@ -142,7 +142,8 @@ GNU Bison NEWS
|
|||||||
README and a Makefile. Not only can they be used to toy with Bison, they
|
README and a Makefile. Not only can they be used to toy with Bison, they
|
||||||
can also be starting points for your own grammars.
|
can also be starting points for your own grammars.
|
||||||
|
|
||||||
There is now a Java example.
|
There is now a Java example, and a simple example in C based on Flex and
|
||||||
|
Bison (examples/c/lexcalc/).
|
||||||
|
|
||||||
** Changes
|
** Changes
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
Example". It is also available on line (maybe with a different version of
|
||||||
Bison):
|
Bison):
|
||||||
https://www.gnu.org/software/bison/manual/html_node/A-Complete-C_002b_002b-Example.html
|
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.
|
the scanner's.
|
||||||
|
|
||||||
<!---
|
<!---
|
||||||
|
|
||||||
Local Variables:
|
Local Variables:
|
||||||
fill-column: 76
|
fill-column: 76
|
||||||
ispell-dictionary: "american"
|
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
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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
|
||||||
--->
|
--->
|
||||||
|
|||||||
34
examples/c/lexcalc/Makefile
Normal file
34
examples/c/lexcalc/Makefile
Normal file
@@ -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)
|
||||||
28
examples/c/lexcalc/README.md
Normal file
28
examples/c/lexcalc/README.md
Normal file
@@ -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/>.
|
||||||
|
--->
|
||||||
27
examples/c/lexcalc/lexcalc.test
Normal file
27
examples/c/lexcalc/lexcalc.test
Normal file
@@ -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
|
||||||
32
examples/c/lexcalc/local.mk
Normal file
32
examples/c/lexcalc/local.mk
Normal file
@@ -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
|
||||||
95
examples/c/lexcalc/parse.y
Normal file
95
examples/c/lexcalc/parse.y
Normal file
@@ -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;
|
||||||
|
}
|
||||||
43
examples/c/lexcalc/scan.l
Normal file
43
examples/c/lexcalc/scan.l
Normal file
@@ -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). */
|
||||||
@@ -16,5 +16,6 @@
|
|||||||
cdir = $(docdir)/%D%
|
cdir = $(docdir)/%D%
|
||||||
dist_c_DATA = %D%/README.md
|
dist_c_DATA = %D%/README.md
|
||||||
|
|
||||||
|
include %D%/lexcalc/local.mk
|
||||||
include %D%/mfcalc/local.mk
|
include %D%/mfcalc/local.mk
|
||||||
include %D%/rpcalc/local.mk
|
include %D%/rpcalc/local.mk
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ all: $(BASE)
|
|||||||
$(CC) $(CFLAGS) -o $@ $<
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
run: $(BASE)
|
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
|
html: $(BASE).html
|
||||||
|
|||||||
Reference in New Issue
Block a user