home *** CD-ROM | disk | FTP | other *** search
- ############################################################################
- #
- # File: recgen.icn
- #
- # Subject: Program to generate context-free recognizer
- #
- # Author: Ralph E. Griswold
- #
- # Date: January 28, 1991
- #
- ###########################################################################
- #
- # 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
-