home *** CD-ROM | disk | FTP | other *** search
- * Program BNF.SNO
- *
- * This program reads a series of definitions which comprise
- * a formal grammar. Sample statement lines are then input, and
- * tested to see if they are legal for the defined grammar.
- *
- * The grammar format used is Backus-Naur Form (BNF). Briefly,
- * TERMINALs are the characters from which language elements are created,
- * and NONTERMINALs are the structures and elements of interest. In the
- * following, NONTERMINALs are enclosed in angle brackets, the string
- * '::=' is used to define a NONTERMINAL, and vertical bar defines
- * alternative choices. The GOAL is the structure against which sample
- * lines are tested.
- *
- * The method used is to convert the BNF definitions to SNOBOL4 patterns.
- * Note that more efficient forms could be used if BNF was extended to
- * allow SNOBOL4 primitives, such as ANY(LETTER) instead of 'A' | 'B' | ...
- *
- * The grammar definitions are read from the file BNF.DAT, and
- * the sample lines are read from INPUT. A test program is provided
- * on file BNF.IN, and can be used by redirecting input:
- *
- * >SNOBOL4 BNF <BNF.IN
- *
- * From STRING AND LIST PROCESSING IN SNOBOL4 by Ralph E. Griswold,
- * by permission of the author.
- * ----------------------------------------------------------------
- *
- * (c) Copyright 1985, 1987 - Catspaw, Incorporated
- *
- &trim = 1
- &anchor = 1
- &case = 0
- &fullscan = 1
- quote = "'"
-
- * Pattern to break apart a non-terminal definition line:
- defpat = '<' break('>') . name '>::=' rem . def
-
- * Pattern to break apart alternatives within a definition:
- altpat = break('|') . alt len(1) | (len(1) rem) . alt
-
- * Pattern to examine sub-pattern within an alternative. There are three
- * forms: '<NONTERMINAL>', 'TERMINAL <NONTERMINAL>', and 'TERMINAL TERMINAL'.
- * Note the use of the cursor operator to assign P the value 1 if SUB is a
- * NONTERMINAL, and 0 if it is a TERMINAL.
- subpat = '<' @p break('>') . sub '>' |
- + @p (len(1) break('<')) . sub | @p (len(1) rem) . sub
-
- * The goal is a NONTERMINAL without a definition:
- goal = '<' break('>') . name
-
- input(.grammar, 2, , 'BNF.DAT') :s(nextl)
- output = 'Cannot open file BNF.DAT' :(end)
-
- nextl line = grammar :f(error)
- line defpat :f(test)
- output = line
-
- * Initialize variable to accumulate the current definition.
- pattern =
-
- * Get next alternative from definition, accumulate a next alternative.
- nexta def altpat = :f(eod)
- pattern = differ(pattern) pattern ' |'
-
- * Get next subpattern for this alternative
- nexts alt subpat = :f(nexta)
-
- * If it's a nonterminal, use unevaluated expression operator:
- pattern = gt(p,0) pattern ' *' sub :s(nexts)
-
- * Otherwise it's a terminal. Put it in quotes:
- pattern = pattern ' ' quote sub quote :(nexts)
-
- * No more alternatives, define this NONTERMINAL and display SNOBOL4 form.
- eod $name = eval(pattern)
- output = name " = " pattern
- output = :(nextl)
-
- * Line with no definition, it must be the GOAL:
- test line goal
- pattern = pos(0) $name rpos(0)
- endfile(2)
- output = 'Enter test lines:'
-
- * Now read sample lines from the input file, and test them.
- testt string = input :f(end)
- output =
- output = string
- string pattern :f(no)
- output = 'is a ' name :(testt)
- no output = 'is not a ' name :(testt)
- end
-