bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/4] examples: add a simple infix calculator in C


From: Akim Demaille
Subject: [PATCH 2/4] examples: add a simple infix calculator in C
Date: Sun, 10 Feb 2019 16:48:52 +0100

Currently we have no simple example: rpcalc in reverse Polish, mfcalc
has functions, and lexcalc is using lex.

* examples/c/calc/Makefile, examples/c/calc/calc.y,
* examples/c/calc/calc.test, examples/c/calc/local.mk: New.
---
 NEWS                        |  5 ++
 TODO                        |  8 ++++
 examples/c/README.md        | 21 +++++++--
 examples/c/calc/Makefile    | 28 +++++++++++
 examples/c/calc/calc.test   | 37 +++++++++++++++
 examples/c/calc/calc.y      | 93 +++++++++++++++++++++++++++++++++++++
 examples/c/calc/local.mk    | 32 +++++++++++++
 examples/c/lexcalc/Makefile |  2 +-
 examples/c/local.mk         |  1 +
 9 files changed, 222 insertions(+), 5 deletions(-)
 create mode 100644 examples/c/calc/Makefile
 create mode 100644 examples/c/calc/calc.test
 create mode 100644 examples/c/calc/calc.y
 create mode 100644 examples/c/calc/local.mk

diff --git a/NEWS b/NEWS
index 39db9104..fab5148c 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,11 @@ GNU Bison NEWS
   When given -fsyntax-only, the diagnostics are reported, but no output is
   generated.
 
+** Documentation
+
+  A new example in C shows an simple infix calculator with a hand-written
+  scanner (examples/c/calc).
+
 * Noteworthy changes in release 3.3.2 (2019-02-03) [stable]
 
 ** Bug fixes
diff --git a/TODO b/TODO
index 9c434c7c..6e7e387e 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,12 @@
 * Bison 3.4
+** doc
+I feel its ugly to use the GNU style to declare functions in the doc.  It
+generates tons of white space in the page, and may contribute to bad page
+breaks.
+
+Also, we seem to teach YYPRINT very early on, although it should be
+considered deprecated: %printer is superior.
+
 ** injection rules
 ** glr.cc
 move glr.c into the yy namespace
diff --git a/examples/c/README.md b/examples/c/README.md
index 9f8bd5ab..6cdbcfe3 100644
--- a/examples/c/README.md
+++ b/examples/c/README.md
@@ -1,9 +1,11 @@
-This directory contains examples of Bison grammar files.
+# Examples in C
+
+This directory contains simple examples of Bison grammar files in C.
 
 Most of them come from the documentation, which should be installed together
 with Bison.  The URLs are provided for convenience.
 
-# rpcalc - Reverse Polish Notation Calculator
+## rpcalc - Reverse Polish Notation Calculator
 The first example is that of a simple double-precision Reverse Polish
 Notation calculator (a calculator using postfix operators). This example
 provides a good starting point, since operator precedence is not an issue.
@@ -11,12 +13,23 @@ provides a good starting point, since operator precedence 
is not an issue.
 Extracted from the documentation: "Reverse Polish Notation Calculator"
 https://www.gnu.org/software/bison/manual/html_node/RPN-Calc.html
 
-# mfcalc - Multi-Function Calculator
-A more complete C example: a multi-function calculator.
+## calc - Simple Calculator
+This example is slightly more complex than rpcalc: it features infix
+operators (`1 + 2`, instead of `1 2 +` in rpcalc), but it does so using a
+unambiguous grammar of the arithmetics instead of using precedence
+directives (%left, etc.).
+
+## mfcalc - Multi-Function Calculator
+A more complete C example: a multi-function calculator.  More complex than
+the previous example.  Using precedence directives to support infix
+operators.
 
 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.
+
 
 <!---
 
diff --git a/examples/c/calc/Makefile b/examples/c/calc/Makefile
new file mode 100644
index 00000000..6221ca9e
--- /dev/null
+++ b/examples/c/calc/Makefile
@@ -0,0 +1,28 @@
+# This Makefile is designed to be simple and readable.  It does not
+# aim at portability.  It requires GNU Make.
+
+BASE = calc
+BISON = bison
+XSLTPROC = xsltproc
+
+all: $(BASE)
+
+%.c %.h %.xml %.gv: %.y
+       $(BISON) $(BISONFLAGS) --defines --xml --graph=$*.gv -o $*.c $<
+
+$(BASE): $(BASE).o
+       $(CC) $(CFLAGS) -o $@ $^
+
+run: $(BASE)
+       @echo "Type arithmetic expressions.  Quit with ctrl-d."
+       ./$<
+
+html: $(BASE).html
+%.html: %.xml
+       $(XSLTPROC) $(XSLTPROCFLAGS) -o $@ $$($(BISON) 
--print-datadir)/xslt/xml2xhtml.xsl $<
+
+CLEANFILES =                                                                   
\
+  $(BASE) *.o $(BASE).[ch] $(BASE).output $(BASE).xml $(BASE).html $(BASE).gv
+
+clean:
+       rm -f $(CLEANFILES)
diff --git a/examples/c/calc/calc.test b/examples/c/calc/calc.test
new file mode 100644
index 00000000..c1f1b07c
--- /dev/null
+++ b/examples/c/calc/calc.test
@@ -0,0 +1,37 @@
+#! /bin/sh
+
+# Copyright (C) 2019 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 -4
+
+cat >input <<EOF
+8 / 2 / 2
+EOF
+run 0 2
+
+cat >input <<EOF
+(1+2) * 3
+EOF
+run 0 9
+run -noerr 0 9 -p
diff --git a/examples/c/calc/calc.y b/examples/c/calc/calc.y
new file mode 100644
index 00000000..f9e19624
--- /dev/null
+++ b/examples/c/calc/calc.y
@@ -0,0 +1,93 @@
+%code top {
+  #include <ctype.h>  /* isdigit. */
+  #include <stdio.h>  /* For printf, etc. */
+  #include <string.h> /* strcmp. */
+
+  int yylex (void);
+  void yyerror (char const *);
+}
+
+%define api.value.type union /* Generate YYSTYPE from these types:  */
+%token <double> NUM "number"
+%type  <double> expr term fact
+
+/* Generate the parser description file.  */
+%verbose
+/* Enable run-time traces (yydebug).  */
+%define parse.trace
+
+/* Formatting semantic values.  */
+%printer { fprintf (yyo, "%g", $$); } <double>;
+
+%% /* The grammar follows.  */
+input:
+  %empty
+| input line
+;
+
+line:
+  '\n'
+| expr '\n'  { printf ("%.10g\n", $1); }
+| error '\n' { yyerrok; }
+;
+
+expr:
+  expr '+' term { $$ = $1 + $3; }
+| expr '-' term { $$ = $1 - $3; }
+| term
+;
+
+term:
+  term '*' fact { $$ = $1 * $3; }
+| term '/' fact { $$ = $1 / $3; }
+| fact
+;
+
+fact:
+  "number"
+| '(' expr ')' { $$ = $2; }
+;
+
+%%
+
+int
+yylex (void)
+{
+  int c;
+
+  /* Ignore white space, get first nonwhite character.  */
+  while ((c = getchar ()) == ' ' || c == '\t')
+    continue;
+
+  if (c == EOF)
+    return 0;
+
+  /* Char starts a number => parse the number.         */
+  if (c == '.' || isdigit (c))
+    {
+      ungetc (c, stdin);
+      scanf ("%lf", &yylval.NUM);
+      return NUM;
+    }
+
+  /* Any other character is a token by itself.        */
+  return c;
+}
+
+/* Called by yyparse on error.  */
+void
+yyerror (char const *s)
+{
+  fprintf (stderr, "%s\n", s);
+}
+
+int
+main (int argc, char const* argv[])
+{
+  int i;
+  /* Enable parse traces on option -p.  */
+  for (i = 1; i < argc; ++i)
+    if (!strcmp(argv[i], "-p"))
+      yydebug = 1;
+  return yyparse ();
+}
diff --git a/examples/c/calc/local.mk b/examples/c/calc/local.mk
new file mode 100644
index 00000000..af06905a
--- /dev/null
+++ b/examples/c/calc/local.mk
@@ -0,0 +1,32 @@
+## Copyright (C) 2019 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/>.
+
+calcdir = $(docdir)/%D%
+
+## ------ ##
+## Calc.  ##
+## ------ ##
+
+check_PROGRAMS += %D%/calc
+TESTS += %D%/calc.test
+EXTRA_DIST += %D%/calc.test
+%C%_calc_SOURCES = %D%/calc.y
+
+# Don't use gnulib's system headers.
+%C%_calc_CPPFLAGS = -I$(top_srcdir)/%D% -I$(top_builddir)/%D%
+
+dist_calc_DATA = %D%/calc.y %D%/Makefile %D%/README.md
+CLEANFILES += %D%/calc %D%/*.o %D%/parse.c %D%/scan.c
+CLEANDIRS += %D%/*.dSYM
diff --git a/examples/c/lexcalc/Makefile b/examples/c/lexcalc/Makefile
index e7c798cd..eccc8767 100644
--- a/examples/c/lexcalc/Makefile
+++ b/examples/c/lexcalc/Makefile
@@ -15,7 +15,7 @@ all: $(BASE)
        $(FLEX) $(FLEXFLAGS) -o$@ $<
 
 scan.o: parse.h
-lexcalc: parse.o scan.o
+$(BASE): parse.o scan.o
        $(CC) $(CFLAGS) -o $@ $^
 
 run: $(BASE)
diff --git a/examples/c/local.mk b/examples/c/local.mk
index a350fea8..dce4b1f7 100644
--- a/examples/c/local.mk
+++ b/examples/c/local.mk
@@ -16,6 +16,7 @@
 cdir = $(docdir)/%D%
 dist_c_DATA = %D%/README.md
 
+include %D%/calc/local.mk
 include %D%/lexcalc/local.mk
 include %D%/mfcalc/local.mk
 include %D%/rpcalc/local.mk
-- 
2.20.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]