summaryrefslogtreecommitdiff
path: root/ipl/progs/recgen.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/progs/recgen.icn')
-rw-r--r--ipl/progs/recgen.icn169
1 files changed, 169 insertions, 0 deletions
diff --git a/ipl/progs/recgen.icn b/ipl/progs/recgen.icn
new file mode 100644
index 0000000..ce47878
--- /dev/null
+++ b/ipl/progs/recgen.icn
@@ -0,0 +1,169 @@
+############################################################################
+#
+# File: recgen.icn
+#
+# Subject: Program to generate context-free recognizer
+#
+# Author: Ralph E. Griswold
+#
+# Date: January 28, 1991
+#
+############################################################################
+#
+# This file is in the public domain.
+#
+############################################################################
+#
+# This program reads a context-free BNF grammar and produces an Icon
+# program that is a recognizer for the corresponding language.
+#
+# Nonterminal symbols are are enclosed in angular brackets. Vertical
+# bars separate alternatives. All other characters are considered to
+# be terminal symbols. The nonterminal symbol on the first line is
+# taken to be the goal.
+#
+# An example is:
+#
+# <expression>::=<term>|<term>+<expression>
+# <term>::=<element>|<element>*<term>
+# <element>::=x|y|z|(<expression>)
+#
+# Characters in nonterminal names are limited to letters and underscores.
+# An underscore is appended for the recognizing procedure name to avoid
+# possible collisions with Icon function names.
+#
+# Lines beginning with an = are passed through unchanged. This allows
+# Icon code to be placed in the recognizer.
+#
+############################################################################
+#
+# Limitations:
+#
+# Left recursion in the grammar may cause the recognizer to loop.
+# There is no check that all nonterminal symbols that are referenced
+# are defined or for duplicate definitions.
+#
+############################################################################
+#
+# Reference:
+#
+# The Icon Programming Language, Second Edition, Ralph E. and Madge T.
+# Griswold, Prentice-Hall, 1990. pp. 180-187.
+#
+############################################################################
+#
+# See also: pargen.icn
+#
+############################################################################
+
+global call # name suffix and parens
+global goal # nonterminal goal name
+global nchars # characters allowed in a nonterminal name
+
+procedure main()
+ local line # a line of input
+
+ call := "_()"
+ nchars := &letters ++ '_'
+
+ while line := read() do { # process lines of input
+ line ? {
+ case move(1) of { # action depends on first character
+ "<": tab(0) ? transprod() # transform the production
+ "=": write(tab(0)) # pass through
+ default: error()
+ } # end case
+ } # end scan
+ } # end while
+
+ write("procedure main()") # write out the main procedure
+ write(" while line := read() do {")
+ write(" writes(image(line))")
+ write(" if line ? (",goal,call," & pos(0)) then ")
+ write(" write(\": accepted\")")
+ write(" else write(\": rejected\")")
+ write(" }")
+ write("end")
+
+end
+
+#
+# Transform a production.
+#
+
+procedure transprod()
+ local sym # the symbol being defined
+
+ {
+ # begin the procedure declaration
+ write("procedure ",sym := tab(many(nchars)),call) &
+ =">::=" # skip definition symbols
+ } | error() # catch syntactic error
+ write(" suspend {") # begin the suspend expression
+ transalts() # transform the alternatives
+ write(" }") # end the suspend expression
+ write("end") # end the procedure declaration
+ write() # space between declarations
+ /goal := sym # first symbol is goal
+
+end
+
+#
+# Transform a sequence of alternatives.
+#
+procedure transalts()
+ local alt # an alternative
+
+ writes(" ") # write indentation
+ while alt := tab(upto('|') | 0) do { # process alternatives
+ writes(" (") # open parenthesis for alternative
+ alt ? transseq() # transform the symbols
+ if move(1) then writes(") |") # if there's more, close the parentheses
+ # and add the alternation.
+ else {
+ write(")") # no more, so just close the parentheses
+ break
+ } # end else
+ } # end while
+
+end
+
+#
+# Transform a sequence of symbols.
+#
+procedure transseq()
+
+ repeat {
+ transsym() # process a symbols
+ if not pos(0) then writes(",") # if there's more, provide concatenation
+ else break # else get out and return
+ } # end while
+
+end
+
+#
+# Transform a symbol.
+#
+procedure transsym()
+
+ if ="<" then { # if it's a nonterminal
+ { # write it with suffix.
+ writes(tab(many(nchars)),call) &
+ =">" # get rid of closing bracket
+ } | error() # or catch the error
+ } # end then
+ # otherwise transform nonterminal string
+ else writes("=",image(tab(upto('<') | 0)))
+
+ return
+
+end
+
+#
+# Issue error message and terminate execution.
+#
+procedure error()
+
+ stop("*** malformed definition: ",tab(0))
+
+end