Annotation of researchv10no/cmd/sml/lib/mlyacc/mlyacc.doc, revision 1.1

1.1     ! root        1: 
        !             2:                         ML-YACC, version 1.0
        !             3: 
        !             4:                         Preliminary Documentation
        !             5:                         for Preliminary Version
        !             6: 
        !             7:                         David R. Tarditi
        !             8:                         Andrew W. Appel
        !             9: 
        !            10:                         Department of Computer Science
        !            11:                         Princeton University
        !            12:                         Princeton, NJ 08544
        !            13: 
        !            14:                         February 1, 1989
        !            15: 
        !            16: (c) 1989 Andrew W. Appel, David R. Tarditi
        !            17: This software comes with ABSOLUTELY NO WARRANTY.
        !            18: This software is subject only to the PRINCETON STANDARD ML SOFTWARE LIBRARY
        !            19: COPYRIGHT NOTICE, LICENSE AND DISCLAIMER, (in the file "COPYRIGHT",
        !            20: distributed with this software). You may copy and distribute this software;
        !            21: see the COPYRIGHT NOTICE for details and restrictions.
        !            22: 
        !            23: Description
        !            24: -----------
        !            25: 
        !            26: This is a preliminary guide to using ML-Yacc. It is not complete documentation.
        !            27: It tells how to invoke ML-Yacc, and the syntax of an ML-Yacc specification.
        !            28: The syntax description assumes the user knows how to use Yacc, and notes the
        !            29: differences between ML-Yacc and Yacc.
        !            30: 
        !            31: Note that version 2.0 will be released at the end of 1989; it has a slightly
        !            32: different interface and much improved error recovery.
        !            33: 
        !            34: ML-Yacc is Yacc-like parser generator for Standard ML.  It generates
        !            35: parsers for LALR languages, like Yacc, and its syntax is very similar to
        !            36: that of Yacc.
        !            37: 
        !            38: It handles syntax errors differently from Yacc.  The parser
        !            39: generated by ML-Yacc will attempt to automatically recover from a
        !            40: syntax error by making a single token insertion, deletion, or substitution.
        !            41: At the moment, only tokens without values can be inserted or substituted.
        !            42: A future version will also insert tokens with values, by providing a
        !            43: mechanism for specifying code to be evaluated for each token that will
        !            44: provided a dummy value.
        !            45: 
        !            46: Syntax Error Recovery Method.
        !            47: -----------------------------
        !            48: 
        !            49: The method used is described in 
        !            50: 
        !            51:         'A Practical Method for LR and LL Syntactic Error Diagnosis and
        !            52:          Recovery', by M. Burke and G. Fisher, ACM Transactions on
        !            53:          Programming Languages and Systems, Vol. 9, No. 2, April 1987,
        !            54:          pp. 164-197.
        !            55: 
        !            56: The partial, deferred method discussed in the article has been
        !            57: implemented.  
        !            58: 
        !            59: This method defers reductions for some number of shifted tokens.  The
        !            60: deferred reductions are kept in a queue, and when an element is pulled
        !            61: from the queue, the reductions are then applied to the value stack.
        !            62: 
        !            63: When a syntax error is encountered, the parser reads some number of tokens
        !            64: ahead.  It then uses the queue of deferred actions to check possible error
        !            65: recoveries.  IMPORTANT:  Since the lexer is several tokens ahead of the
        !            66: execution of semantic actions, the semantic routines CANNOT influence the
        !            67: action of the lexer in any significant way.  Example 1:  it is hard to imagine
        !            68: how to compile "typedef" in C.  Example 2:  the "infix" operators of ML must be
        !            69: treated as ordinary identifiers and handled specially by the semantic actions.
        !            70: 
        !            71: 
        !            72: Invoking ML-Yacc
        !            73: ----------------
        !            74: 
        !            75: Use "mlyacc.sml"; this will create a structure ParseGen.  The function
        !            76: ParseGen.parseGen creates a program for a parser from an input
        !            77: specification.  It takes a string argument -- the name of the file
        !            78: containing the input specification.  The output file name is 
        !            79: determined by appending ".sml" to the input file name.
        !            80: 
        !            81: Using the parser created by ML-Yacc
        !            82: -----------------------------------
        !            83: 
        !            84: Invoking the parser
        !            85: -------------------
        !            86: 
        !            87: After following the commands above, a structure whose name was
        !            88: specified by the user will exist.  Three of the components are relevent to
        !            89: the user:
        !            90: 
        !            91:         HDR: a structure containing values declared in the "user routines"
        !            92:              section of the ML-Yacc specification.
        !            93: 
        !            94:         LexValue: a structure containing constructors for returning tokens
        !            95:                   and their values to the parser from the lexical analyzer.
        !            96: 
        !            97:         parse: a function which takes a lexing function and a pair of integers
        !            98:                and parses the input from the lexing functions.
        !            99:                The lexing function must returns values of type LexValue.V
        !           100:                The pair of integers specifies the defer and lookahead
        !           101:                parameters for the error-recovery algorithm.
        !           102:                For interactive parsers, (0,0) is suggested; for
        !           103:               good error recovery, (10,5) is suggested.
        !           104: 
        !           105: Creating the lex function
        !           106: -------------------------
        !           107: 
        !           108: The lexing function must have the following form:
        !           109: 
        !           110: lexer : unit -> LexValue.V
        !           111: 
        !           112: This lexical-analyzer interface is exactly that provided by ML-Lex, an ML
        !           113: version of Lex.  The user should include the statement 
        !           114: 'open {structure name}.LexValue'
        !           115: in the user routines section of his ML-Lex specification.  This will
        !           116: make the components of HDR and the constructors for terminals available to
        !           117: the lex actions.  The lex actions should all return these constructors as
        !           118: values.
        !           119: 
        !           120: The names of the constructors are the same as the terminal names used
        !           121: in the ML-Yacc specification.   The constructors for those terminals
        !           122: that have values take only values with the same type as the terminal,
        !           123: of course.  Those for terminals with no values are nullary constructors.
        !           124: 
        !           125: A sample ML-Lex specification is given at the end of this document.
        !           126: 
        !           127: Tying the lexer and parser together
        !           128: -----------------------------------
        !           129: 
        !           130: The use of ML-Lex is suggested but not required.
        !           131: The user should create the lexing function using makeLexer, and then
        !           132: pass this function to the function C.parse.   Here is some code which
        !           133: does this.
        !           134: 
        !           135: fun parse(infile) = 
        !           136:      let val in_str = open_in infile
        !           137:          val lexer = mlex.makeLexer(input in_str)
        !           138:          val p = C.parse lexer (5,5)
        !           139:      in (close_in in_str; p)
        !           140:      end
        !           141: 
        !           142: Grammar specifications
        !           143: ----------------------
        !           144: 
        !           145: The ML-Yacc specification is very similar to a Yacc specification.  The
        !           146: specification has the following form:
        !           147: 
        !           148: {user routines}
        !           149: %%
        !           150: {declarations}
        !           151: %%
        !           152: {rules}
        !           153: 
        !           154: The declarations section contains the following declarations:
        !           155: 
        !           156: %term           %eof    %left   %nonassoc   %verbose    %subst      %default
        !           157: %nonterm        %start  %right  %structure  %prefer     %keyword
        !           158: 
        !           159: User routines
        !           160: -------------
        !           161: 
        !           162: The user routines section must contain the following:
        !           163: 
        !           164:         type Lineno = ...
        !           165:         val  lineno : Lineno ref = ...
        !           166:         val error :  string -> Lineno -> unit
        !           167:              which is used to print error messages.
        !           168: 
        !           169: The Lineno type is some representation of a position in the input file, so that
        !           170: error messages can be keyed to the line number (or character position, etc.)
        !           171: of the token that "caused" the error.  If this is not necessary, Lineno can be
        !           172: just "unit".
        !           173: 
        !           174: %verbose
        !           175: --------
        !           176: 
        !           177: Generate a y.output file, which gives a verbose description of the
        !           178: tables created from the grammar.
        !           179: 
        !           180: %structure
        !           181: ----------
        !           182: 
        !           183: The name of the structure in which to place the parser should be specifed
        !           184: using the statement %structure {structure name}
        !           185: 
        !           186: Terminals and nonterminals
        !           187: --------------------------
        !           188: 
        !           189: All terminals must be declared in the %term statement.  All
        !           190: nonterminals must be declared in the %nonterm statement.  The
        !           191: statements both have a form similar to that of an ML constructor
        !           192: statement.
        !           193: 
        !           194: Each symbol may be followed by the phrase "of <type>".
        !           195: Multiple symbols must be separated by a bar: '|'.  At least one
        !           196: symbol must appear in each statement.
        !           197: 
        !           198: The user is cautioned not to use ML reserved words for terminal or
        !           199: nonterminal names.  The program produced by ML-Yacc will not load correctly.
        !           200: The <type> may be any valid ML type expression.
        !           201: 
        !           202: A terminal name for the eof terminal must also be supplied.
        !           203: 
        !           204: The start nonterminal and the eof terminal
        !           205: ------------------------------------------
        !           206: 
        !           207: The eof terminal must be named in the %eof statement.  Suppose the
        !           208: eof terminal were EOF.  Then the %eof statement would be
        !           209: 
        !           210: %eof EOF
        !           211: 
        !           212: The start terminal should be named in the %start statement.  If one
        !           213: is not supplied, the lhs of the first rule will be used.
        !           214: 
        !           215: Precedence
        !           216: ----------
        !           217: 
        !           218: Precedence is specified in the same manner as yacc.  The terminals
        !           219: are listed after the %left, %right, or %nonassoc statement.  The
        !           220: statements are in order of ascending (tighter binding) precedence.
        !           221: 
        !           222: Precedence operates like it does in yacc, except for %nonassoc.
        !           223: Like YACC, each rule is assigned the precedence of its rightmost terminal.
        !           224: In the case of a shift/reduce conflict the precedence of the terminal
        !           225: in the shift and the precedence of the rule in the reduce are compared.
        !           226: If the terminal has a higher precedence, the shift is performed.  If the
        !           227: rule has a higher precedence, the reduce is performed.  If the terminal
        !           228: and the rule have the same precedence, the associativity of the terminal
        !           229: is used to resolve the conflict.  If the terminal is left associative,
        !           230: we reduce.  If the terminal is right associative, we shift.  If the
        !           231: terminal is nonassociative we print an error message and shift.
        !           232: 
        !           233: Thus %nonassoc does not produce a fatal error if the associativity of a
        !           234: nonassociative terminal is used to resolve a conflict.  A warning message is
        !           235: printed, though, about this, and a shift is planted.  The shift causes the
        !           236: nonassociative terminal to default to right associativity.
        !           237: 
        !           238: Reduce/reduce conflicts are fatal in ML-Yacc, unlike in yacc.  There is
        !           239: no resolution of reduce/reduce conflicts based on rule ordering.
        !           240: 
        !           241: The %prec tag may be used to alter the precedence for a rule.  It is
        !           242: described below under the Rules section.
        !           243: 
        !           244: Information for an error correction algorithm.
        !           245: ----------------------------------------------
        !           246: 
        !           247: The following keywords allow the user to specify information that may improve
        !           248: recovery:
        !           249: 
        !           250:         %keyword                - a list of tokens which are keywords
        !           251:         %prefer                 - a list of tokens which are preferred
        !           252:                                   for insertion
        !           253:         %subst                  - a list of preferred substitions for
        !           254:                                   certain tokens.
        !           255:         %default                - value to be used for inserted tokens
        !           256:                                     that carry values. (not yet implemented)
        !           257: 
        !           258: %keyword and %prefer should each be followed by a list of tokens.
        !           259: 
        !           260: %subst has the following syntax: 
        !           261: 
        !           262:    %subst {token} for {token} |  ...   | {token} for {token}
        !           263: 
        !           264: Rules
        !           265: -----
        !           266: 
        !           267: The rule section consists of a list of rules.
        !           268: 
        !           269: Each rule has the syntax:
        !           270: 
        !           271: {lhs nonterminal} : {rhs symbol list}   ({value of same type as nonterminal,
        !           272:                                          or any type if the nonterminal has
        !           273:                                          none }) 
        !           274: 
        !           275:  or
        !           276: 
        !           277:  {lhs nonterminal} : {rhs symbol list} %prec {terminal} ( ... value ...)
        !           278: 
        !           279: The second form gives the rule the same precedence as the terminal.
        !           280: 
        !           281: The | may be used to separate multiple rhs's with the same lhs.
        !           282: 
        !           283: A null rhs may be specified by simply by having an empty rhs symbol list.
        !           284: 
        !           285: The ( ... value ... ) part is not optional.  It may be empty, though, if
        !           286: the lhs nonterminal has no type associated with it.
        !           287: 
        !           288: Values
        !           289: ------
        !           290: 
        !           291: The value for a symbol on the rhs of a rule is in a variable
        !           292: {symbol}N.  N is the number of occurrences of the symbol in the rhs,
        !           293: up to and including the symbol.  Suppose we had a specification of
        !           294: the form:
        !           295: 
        !           296: %term ... PLUS ...
        !           297: %nonterm ... EXP of int ...
        !           298: ...
        !           299: %%
        !           300: 
        !           301: EXP : EXP PLUS EXP 
        !           302: 
        !           303: Then the action could contain (EXP1 + EXP2).  EXP1 is the value of the
        !           304: first occurrence of EXP on the rhs, while EXP2 is the value of the second
        !           305: occurrence on the rhs.
        !           306: 
        !           307: If a symbol has no type associated with it, it has no value associated
        !           308: with it.  Attempting to use PLUS1, in the above example, would result
        !           309: later in a compilation error.
        !           310: 
        !           311: Any value returned by a rule whose left hand side has no type associated with
        !           312: it is ignored.  The ML code associated with such rules may return any kind of
        !           313: value; it will be executed for possible side-effects.
        !           314: 
        !           315: If a terminal or nonterminal occurs only once on the rhs of a rule, its
        !           316: value is also in {symbol}, as well as in {symbol}1
        !           317: 
        !           318: Bugs
        !           319: ----
        !           320: There should be a better way for semantic-action routines to print out errors
        !           321: and get the appropriate range of line numbers in the message automatically.
        !           322: 
        !           323: Functors should be used to make the lexer more independent of the parser.
        !           324: Speed should be improved in future versions.
        !           325: 
        !           326: Sample specification
        !           327: --------------------
        !           328: (* sample.grm *)
        !           329: type Lineno = int
        !           330: val lineno = ref 1
        !           331: fun error s l = output std_out 
        !           332:         ("line " ^ makestring (l:int) ^ ":" ^ s ^ "\n")
        !           333: fun lookup s = ordof(s,0) - ord("a")+1
        !           334: %%
        !           335: %structure Calc
        !           336: %eof   EOF
        !           337: %start START
        !           338: 
        !           339: %left SUB PLUS
        !           340: %left TIMES DIV
        !           341: %right CARAT
        !           342: 
        !           343: %term ID of string | NUM of int | PLUS | TIMES | PRINT | EOS | EOF |
        !           344:         CARAT | DIV | SUB
        !           345: %nonterm EXP of int | START | STMT | STMT_LIST
        !           346: 
        !           347: %%
        !           348:   START : STMT_LIST     ()
        !           349:   STMT_LIST : STMT_LIST STMT EOS ()
        !           350:   STMT_LIST : ()
        !           351:   STMT : PRINT EXP      (print EXP; print "\n"; flush_out std_out)
        !           352:   STMT : EXP            ()
        !           353:   EXP : NUM             (NUM)
        !           354:       | ID              (lookup ID)
        !           355:       | EXP PLUS EXP    (EXP1+EXP2)
        !           356:       | EXP TIMES EXP   (EXP1*EXP2)
        !           357:       | EXP DIV EXP     (EXP1 div EXP2)
        !           358:       | EXP SUB EXP     (EXP1-EXP2)
        !           359:       | EXP CARAT EXP   (let fun e (m,0) = 1
        !           360:                                 | e (m,i) = m*e(m,i-1)
        !           361:                          in e (EXP1,EXP2)       
        !           362:                          end)
        !           363: 
        !           364: Sample ML-Lex specification
        !           365: ---------------------------
        !           366: (* sample.lex *)
        !           367: open Calc.LexValue
        !           368: type lexresult=V
        !           369: val eof = fn () => EOF
        !           370: %%
        !           371: alpha=[A-Za-z];
        !           372: digit=[0-9];
        !           373: ws = [\ \t\n];
        !           374: %%
        !           375: {ws}+    => (lex());
        !           376: {digit}+ => (NUM (revfold (fn (a,r) => ord(a)-ord("0")+10*r) (explode yytext) 0));
        !           377: "+"      => (PLUS);
        !           378: "*"      => (TIMES);
        !           379: ";"      => (EOS);
        !           380: {alpha}+ => (if yytext="print" then PRINT else ID yytext);
        !           381: "-"      => (SUB);
        !           382: "^"      => (CARAT);
        !           383: "/"      => (DIV);
        !           384: .        => (Calc.HDR.error ("ignoring bad character " ^ yytext); lex());
        !           385: 
        !           386: 
        !           387: Sample "main" module
        !           388: --------------------
        !           389: (* sample.sml *)
        !           390: structure Sample =
        !           391:    struct
        !           392:       fun run filename = 
        !           393:             (* more suitable for non-interactive use *)
        !           394:           let val in_str = open_in filename
        !           395:               val lexer =  Mlex.makeLexer (input in_str)
        !           396:               val p = (Calc.HDR.lineno := 0;
        !           397:                        Calc.parse lexer (5,5))
        !           398:            in (close_in in_str; p)
        !           399:            end
        !           400:     
        !           401:       fun run_std_in () =
        !           402:             (* more suitable for interactive use *)
        !           403:         let val lexer = Mlex.makeLexer (fn _ => input_line std_in)
        !           404:             val p = (Calc.HDR.lineno := 0;
        !           405:                        Calc.parse lexer (0,0))
        !           406:          in p
        !           407:         end
        !           408:    end
        !           409: 
        !           410: Sample input
        !           411: ------------
        !           412: (* sample.input, contains an intentional syntax error *)
        !           413: print 4+2;
        !           414: a+b
        !           415: print b*c;
        !           416: 
        !           417: 
        !           418: How to try the sample program
        !           419: ----------------------------
        !           420: 
        !           421: % sml
        !           422: - use "mlyacc.sml";  (* load the parser generator *)
        !           423: - use "lexgen.sml";  (* load the lexical analyzer generator *)
        !           424: - open LexGen ParseGen;
        !           425: - exportML "yacclex"; (* save the image for later use *)
        !           426: 
        !           427: - lexGen "sample.lex";  (* creates the file sample.lex.sml *)
        !           428: - parseGen "sample.grm"; (* creates the file sample.grm.sml *)
        !           429: - ^D            (* exiting here is optional, of course *)
        !           430: 
        !           431: % sml
        !           432: - use "sample.grm.sml";     (* compile the parser *)
        !           433: - use "sample.lex.sml";     (* compile the lexer *)
        !           434: - use "sample.sml";         (* compile the main module *)
        !           435: - Sample.run "sample.input"; (* run the sample program *)
        !           436: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.