1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570 |
- symbolic;
- spool "lalr.log";
- on comp, backtrace;
- unglobal '(!*raise);
- fluid '(!*raise);
- %=============================================================================
- % The file provides parser support for Lisp. The file contains three
- % major sections. The first is a lexical analyser, which has been
- % coded to support RLISP and Standard Lisp. Its interface is modelled after
- % the one used with the lex/yacc combination commonly used with Unix.
- %
- % The second section is the generic part of an LR parser. It requires
- % tables to tell it what actions to take, and calls the lexical analyser to
- % obtain tokens.
- %
- % The final part is an LALR(1) parser generator, which can take the
- % specification of a grammar and construct tables that direct the
- % generic parser skeleton.
- %
- %=============================================================================
- %
- % This is a lexical anaylser for use with RLISP. Its interface is
- % styles after the one needed by yacc, in that it exports a function
- % called yylex() that returns as a value a numeric category code, but
- % sets a variable yylval to hold further information about the token
- % just parsed. Single character objects are coded as their (ASCII?) code
- % [leaving this code non-portable to machines with other encodings?].
- % Other things must have been given 'lex_code properties indicate the
- % associated category code. This lexer handles ' and ` as special prefix
- % characters that introduce Lisp-stype s-expressions. and it knows about
- % RLISP-style comments and a few diphthongs. It also supports some
- % simple preprocessor directives.
- %
- % Arthur Norman. April 1995
- fluid '(!*raise !*lower !*echo);
- global '(lex_char yylval last64 last64p which_line);
- % I keep a circular buffer with the last 64 characters that have been
- % read. Initially the buffer contains NILs rather than characters, so I can
- % tell when it is only partially filled.
- smacro procedure yyreadch();
- << last64p := last64p + 1;
- if last64p = 64 then last64p := 0;
- lex_char := readch();
- if lex_char = !$eol!$ then which_line := which_line + 1;
- putv(last64, last64p, lex_char);
- lex_char >>;
- symbolic procedure yyerror msg;
- begin
- scalar c;
- terpri();
- princ "+++++ Parse error at line "; prin which_line; princ ":";
- if atom msg then msg := list msg;
- for each s in msg do << princ " "; princ s >>;
- terpri();
- for i := 1:64 do <<
- last64p := last64p + 1;
- if last64p = 64 then last64p := 0;
- c := getv(last64, last64p);
- if c = !$eof!$ then princ "<EOF>"
- else if not (c = nil) then princ c >>;
- if not (c = !$eol!$) then terpri()
- end;
- % Before a succession of calls to yylex() it is necessary to
- % ensure that lex_char is set suitably and that the circular buffer
- % used to store characters for error messages is ready for use.
- symbolic procedure start_parser();
- << last64 := mkvect 64;
- last64p := 0;
- which_line := 1;
- yyreadch() >>;
- %
- % The following version of YYLEX provides RLISP with a facility for
- % conditional compilation. The protocol is that text is included or
- % excluded at the level of tokens. Control by use of new reserved
- % tokens !#if, !#else and !#endif. These are used in the form:
- % !#if (some Lisp expression for use as a condition)
- % ... RLISP input ...
- % !#else
- % ... alternative RLISP input ...
- % !#endif
- %
- % The form
- % !#if C1 ... !#elif C2 ... !#elif C3 ... !#else ... !#endif
- % is also supported.
- %
- % Conditional compilation can be nested. If the Lisp expression used to
- % guard a condition causes an error it is taken to be a FALSE condition.
- % It is not necessary to have an !#else before !#endif if no alternative
- % text is needed. Although the examples here put !#if etc at the start of
- % lines this is not necessary (though it may count as good style?). Since
- % the condtion will be read using RLISPs own list-reader there could be
- % condtional compilation guarding parts of it - the exploitation of that
- % possibility is to be discouraged!
- %
- % Making the condition a raw Lisp expression makes sure that parsing it
- % is easy. It makes it possible to express arbitrary conditions, but it is
- % hoped that most conditions will not be very elaborate - things like
- % !#if (not (member 'csl lispsystem!*))
- % error();
- % !#else
- % magic();
- % !#endif
- % or
- % !#if debugging_mode % NB if variable is unset that counts as nil
- % print "message"; % so care should be taken to select the most
- % !#endif % useful default sense for such tests
- % should be about as complicated as reasonable people need.
- %
- % Two further facilities are provided:
- % !#eval (any lisp expression)
- % causes that expression to be evaluated at parse time. Apart from any
- % side-effects in the evaluation the text involved is all ignored. It is
- % expected that this will only be needed in rather curious cases, for instance
- % to set system-specific options for a compiler.
- %
- % !#define symbol value
- % where the value should be another symbol, a string or a number, causes
- % the first symbol to be mapped onto the second value wherever it occurs in
- % subsequent input. No special facility for undoing the effect of a
- % !#define is provided, but the general-purpose !#eval could be used to
- % remove the '!#define property that is involved.
- %
- % NOTE: The special symbols !#if etc are NOT recognised within Lisp
- % quoted expressions, so test like the following will be
- % ineffective:
- % a := '(
- % P
- % !#if q_is_wanted
- % Q
- % !#endif
- % Q);
- % but on the other hand code like
- % if sym = '!#if then ...
- % behaves the way that had probably been wanted. Unlike the C
- % preprocessor, this system recognizes directives within rather than
- % just at the start of lines.
- symbolic procedure yylex();
- begin
- scalar w, done;
- % I take a rather robust view here - words that are intended to be used as
- % keywords may not be written with included escape characters. Thus for
- % instance this lexer will view "be!gin" or "!begin" as being a simple
- % symbol and NOT being the keyword "begin".
- w := lex_basic_token();
- % The "while not done" loop is so that I can restart the scan after seeing
- % a pre-processor directive such as !#if.
- while not done do <<
- % The word "COMMENT" introduces a comment that terminates at the next ";"
- % or "$".
- while yylval = 'comment and
- w = '!:symbol_or_keyword do <<
- while not (lex_char = '!; or lex_char = '!$) do
- yyreadch();
- yyreadch();
- w := lex_basic_token() >>;
- % If a word was spelt out directly (without any escape characters in it) it
- % may be a keyword - if it is, then convert it here.
- if w = '!:symbol_or_keyword then <<
- if w := get(yylval, '!#define) then <<
- yylval := cdr w;
- w := car w >>
- else <<
- if done := get(yylval, 'lex_code) then w := done
- else if flagp(yylval, 'rlis) then
- w := get('rlistat, 'lex_code)
- else if flagp(yylval, 'endstat) then
- w := get('endstat, 'lex_code)
- else w := get('!:symbol, 'lex_code);
- done := t >> >>
- % A word with escapes in might be a pre-processor directive.
- else if w = '!:symbol then <<
- if yylval eq '!#if then <<
- read_s_expression();
- w := lex_conditional yylval >>
- else if yylval eq '!#else or
- yylval eq '!#elif then <<
- yylval := nil;
- w := lex_skipping(w, nil) >>
- else if yylval eq '!#endif then w := lex_basic_token()
- else if yylval eq '!#eval then <<
- read_s_expression();
- errorset(yylval, nil, nil);
- w := lex_basic_token() >>
- else if yylval eq '!#define then <<
- read_s_expression();
- w := yylval; % Ought to be a symbol
- done := read_s_expression();
- if idp w then put(w, '!#define, done . yylval);
- w := lex_basic_token();
- done := nil >>
- else <<
- w := get('!:symbol, 'lex_code);
- done := t >> >>
- else if numberp w then <<
- % Now gobble up extra characters for multi-character operators (eg ">=").
- % Note that I only look one character ahead here.
- while done := atsoc(lex_char, get(yylval, 'lex_dipthong)) do <<
- w := cdr done;
- yylval := cdr w;
- w := get(car w, 'lex_code);
- yyreadch() >>;
- if done := get(yylval, '!#define) then <<
- yylval := cdr done;
- w := car done;
- done := nil >>
- else done := t >>
- else <<
- done := t;
- w := get(w, 'lex_code) >> >>;
- return w
- end;
- % If, when reading ordinary text, I come across the token !#if I read
- % the expression following. If that evaluates to TRUE I just keep on
- % on reading. So the sequence "!#if t" is in effect ignored. Then
- % if later on I just ignore an "!#endif" all will be well. If on the other
- % hand the expression evaluates to NIL (or if evaluation fails), I will
- % call lex_skipping() to discard more tokens (up to and including
- % the next "!#else", "!#elif t" or "!endif").
- symbolic procedure lex_conditional x;
- begin
- scalar w;
- w := lex_basic_token();
- x := errorset(x, nil, nil);
- if errorp x or null car x then return lex_skipping(w, nil)
- else return w
- end;
- % I call lex_skipping when I find "!#if nil" or "!#else" or "!#elif"
- % that is processed. When a top-level "!#else" or "!#elif" is found it
- % is discarded before calling lex_skipping, since it must follow a
- % successful "!#if" and hence introduce material to be thrown away.
- symbolic procedure lex_skipping(w, x);
- begin
- scalar done;
- % In this code x keep track of the depth of testing of "!#if" constructions
- while not done do <<
- if w = 0 then done := t % End of file
- else <<
- if w = '!:symbol then <<
- if yylval = '!#endif then <<
- if null x then done := t
- else x := cdr x >>
- else if yylval = '!#if then x := nil . x
- else if yylval = '!#else and null x then done := t
- else if yylval = '!#elif and null x then <<
- read_s_expression();
- done := errorset(yylval, nil, nil);
- if errorp done or null car done then done := nil >> >>;
- w := lex_basic_token() >> >>;
- return w
- end;
- % In some cases RLISP operators are made up out of two (or more) characters.
- % I map '**' onto '^', and >=, <= onto GEQ and LEQ.
- % ":=" becomes SETQ. I turn << and >> onto symbols that can not be
- % read directly (!:lsect and !:rsect).
- % This means that the system that sets up lex_code properties had really
- % better make sure that it gives setq, geq, leq, !:rsect and !:lsect values.
- put('!*, 'lex_dipthong, '((!* !^ . !^)));
- put('!:, 'lex_dipthong, '((!= setq . setq)));
- put('!>, 'lex_dipthong, '((!= geq . geq),
- (!> !:rsect . !:rsect)));
- put('!<, 'lex_dipthong, '((!= leq . leq),
- (!< !:lsect . !:lsect)));
- put('!^, 'lex_code, char!-code '!^);
- % lex_basic_token() will read the next token from the current input stream and
- % leave a value in yylval to show what was found. It does not handle the
- % word "comment", nor does it consolidate things like ':' followed by '=' into
- % ':='. Those steps are left to yylex(). But lex_basic_token() does recognize
- % the quote prefix, as in '(lisp expression). The return value is numeric
- % for single-character tokens, but otherwise a descriptive symbol.
- % Some people would consider the Lisp dialect that I am using here to be
- % significantly flawed, in that I need to build symbols, numbers and
- % strings up as lists, and then use COMPRESS to make the real objects. The
- % CONS operations involved can be seen as an overhead, and going back to
- % something like the VERY old-fashioned clearbuff/pack/boffo world might
- % avoid that.
- symbolic procedure lex_basic_token();
- begin
- scalar r, w;
- % First skip over whitespace. Note that at some stage in the future RLISP
- % may want to make newlines significant and partially equivalent to
- % semicolons, but that is not supported at present.
- while lex_char = '! or lex_char = !$eol!$ or
- (lex_char = '!% and <<
- while not (lex_char = !$eol!$ or lex_char = !$eof!$) do
- yyreadch();
- t >>) do yyreadch();
- % Symbols start with a letter or an escaped character and continue with
- % letters, digits, underscores and escapes.
- if liter lex_char or
- (lex_char = '!! and begin
- scalar !*raise, !*lower; % Rebind !*raise & !*lower to avoid..
- r := lex_char . r; % case folding when the next character..
- yyreadch(); % is read.
- return (w := t) end) then <<
- r := lex_char. r;
- while liter(yyreadch()) or
- digit lex_char or
- lex_char = '!_ or
- (lex_char = '!! and begin
- scalar !*raise, !*lower;
- r := lex_char . r;
- yyreadch();
- return (w := t) end) do
- r := lex_char . r;
- % If there was a '!' in the word I will never treat it as a keyword.
- yylval := compress reversip r;
- return if w then '!:symbol else '!:symbol_or_keyword >>
- % Numbers are either integers or floats. A floating point number is
- % indicated by either a point "." or an exponent marker "e". In the code
- % here I keep a flag (in w) to indicate if I had a floating or integer
- % value, but in the end I ignore this and hand back the lexical category
- % :number in both cases.
- else if digit lex_char then <<
- r := list lex_char;
- while digit (yyreadch()) do r := lex_char . r;
- if lex_char = '!. then <<
- w := t; % Flag to indicate floating point
- r := lex_char . r;
- while digit (yyreadch()) do r := lex_char . r >>;
- % I permit the user to write the exponent marker in either case.
- if lex_char = '!e or lex_char = '!E then <<
- % If the input as 1234E56 I expand it as 1234.0E56
- if not w then r := '!0 . '!. . r;
- w := t;
- r := '!e . r;
- yyreadch();
- if lex_char = '!+ or lex_char = '!- then <<
- r := lex_char . r;
- yyreadch() >>;
- % If there is no digit written after "E" I insert a zero. Thus overall the
- % input 17E gets treated as 17.0E0
- if not digit lex_char then r := '!0 . r
- else <<
- r := lex_char . r;
- while digit (yyreadch()) do r := lex_char . r >> >>;
- yylval := compress reversip r;
- return '!:number >>
- % Strings are enclosed in double-quotes, and "abc""def" is a string with
- % a double-quote mark within it. Note no case folding on characters in a
- % string.
- else if lex_char = '!" then <<
- begin
- scalar !*raise, !*lower;
- repeat <<
- r := lex_char . r;
- while not ((yyreadch()) = '!") do r := lex_char . r;
- r := lex_char . r;
- yyreadch() >> until not (lex_char = '!");
- end;
- yylval := compress reversip r;
- return '!:string >>
- % "'" and "`" introduce Lisp syntax S-expressions
- else if lex_char = '!' then <<
- yyreadch();
- read_s_expression();
- yylval := list('quote, yylval);
- return '!:list >>
- else if lex_char = '!` then <<
- yyreadch();
- read_s_expression();
- yylval := list('backquote, yylval);
- return '!:list >>
- else <<
- yylval := lex_char;
- % I take special notice of end of file, since it is fairly drastic.
- % In particular I do not attempt to advance lex_char beyond it. So I do
- % TWO things here: I avoid advancing the input, and I return the code 0
- % as an end-of-file indication.
- if yylval = !$eof!$ then return 0
- else <<
- yyreadch();
- return char!-code yylval >> >>
- end;
- %
- % I use a hand-written recursive descent parser for Lisp S-expressions
- % mainly because the syntax involved is so VERY simple. A rough sketch of
- % the syntax required is given here, but in reality (in part because I do
- % not want to have to report syntax errors) I implement a more liberal
- % syntax, especially as it relates to dotted-pair notation. This of course
- % is one of the natural dangers in using recursive descent... the syntax
- % actually parsed is only properly defined by direct reference to the code.
- %
- % s_tail = ")" |
- % "." s_expr ")" |
- % s_expr s_tail;
- %
- % s_vectail = "]" |
- % s_expr s_vectail;
- %
- % s_expr = symbol |
- % number |
- % string |
- % "(" s_tail |
- % "[" s_vectail |
- % "'" s_expr |
- % "`" s_expr |
- % "," s_expr |
- % ",@" s_expr;
- global '(dot_char rpar_char rsquare_char);
- dot_char := char!-code '!.;
- rpar_char := char!-code '!);
- rsquare_char := char!-code '!];
- symbolic procedure read_s_expression();
- <<
- % At the start of an S-expression I want to check for the characters
- % "(", "[" and ",". Thus I need to skip whitespace.
- while lex_char = '! or lex_char = '!$eol!$ do yyreadch();
- if lex_char = '!( then begin
- scalar r, w, w1;
- yyreadch();
- w := read_s_expression();
- while not (w = rpar_char or w = dot_char or w = 0) do <<
- r := yylval . r;
- % Note that at the end of the list read_s_expression() will read the ")"
- % as a token.
- w := read_s_expression() >>;
- if not w = dot_char then yylval := reversip r
- else <<
- read_s_expression(); % Thing after the "."
- w := yylval;
- % Reverse the list putting a dotted item on the end.
- while r do <<
- w1 := cdr r;
- rplacd(r, w);
- w := r;
- r := w1 >>;
- yylval := w;
- % I will be somewhat liberal about syntactic problems with dotted pair
- % notation, since it is unclear how I can usefully report or repair errors.
- while lex_char = '! or lex_char = '!$eol!$ do
- yyreadch();
- % When I find a ")" I do not read beyond it immediately, but reset lex_char
- % to whitespace. This may help prevent unwanted hangups in interactive use.
- if lex_char = '!) then lex_char := '! >>;
- return '!:list end
- % "[" introduces a simple vector.
- else if lex_char = '![ then begin
- scalar r, w, w1;
- yyreadch();
- w := read_s_expression();
- w1 := -1;
- while not (w = rsquare_char or w = 0) do <<
- r := yylval . r;
- w1 := w1 + 1;
- w := read_s_expression() >>;
- % Create a vector of the correct size and copy information into it.
- w := mkvect w1;
- r := reversip r;
- w1 := 0;
- while r do <<
- putv(w, w1, car r);
- w1 := w1 + 1;
- r := cdr r >>;
- yylval := w;
- return '!:list end
- % I spot "," and ",@" here, and should wonder if I should (a) police that
- % they are only expected to make sense within the scope of a "`" and (b)
- % whether I ought to expand them in terms of LIST, CONS, APPEND etc here.
- % For now I just hand back markers that show where they occured.
- else if lex_char = '!, then <<
- yyreadch();
- if lex_char = '!@ then <<
- yyreadch();
- read_s_expression();
- yylval := list('!,!@, yylval) >>
- else <<
- read_s_expresssion();
- yylval := list('!,, yylval) >>;
- 'list >>
- % Care with ")" and "]" not to read ahead further than is essential.
- else if lex_char = '!) or lex_char = '!] or lex_char = '!. then <<
- yylval := lex_char;
- lex_char := '! ;
- char!-code yylval >>
- % In most cases (including "'" and "`") I just hand down to read a token.
- % This covers the cases of symbols, numbers and strings.
- else lex_basic_token() >>;
- %=============================================================================
- % Here I have a general-purpose LR(1) parser skeleton. This needs to
- % have a source of tokens, and some tables that will direct its actions.
- % The format of the tables required by this code will be a little curious,
- % mainly because they represent some attempt to compact the information that
- % is needed. Note that the CSL functions mkvect16, putv16, getv16 are
- % somewhat similar to the regular mkvect, putv and getv, but may be used
- % if the vector contents will always be 16-bit fixnums.
- global '(!*verbose);
- !*verbose := t; % How much will the parset-generator print?
- global '(goto_index goto_old_state goto_new_state);
- % For each terminal I have a pointer (stored in goto_index) into
- % a pair of vectors, goto_old_state and goto_new_state. The first of these
- % holds states that I might be in, and the second holds the ones I must
- % move into after a reduction has been performed. In the goto_old_state
- % table the value "-1" is taken to match any state that I am attempting
- % to look up. Thus it can be used to terminate a segment of the table. I am
- % entitled to let undefined locations in the goto table respond with
- % any value that just happens.
- smacro procedure get_goto(state, non_terminal);
- << w1 := getv16(goto_index, non_terminal);
- while not (((w2 := getv16(goto_old_state, w1)) = -1) or
- w2 = state) do w1 := w1 + 1;
- getv16(goto_new_state, w1) >>;
- global '(action_index, action_terminal action_result);
- % In a rather similar way, actions are found via an association-list
- % like look-up in a table. In this table a strictly positive number n stands
- % for (SHIFT n) [observe that if I reserve zero as the number of the
- % initial state of my augmented grammar I can never need to shift into
- % state 0]. The value 0 in the table represents ACCEPT. This leaves
- % nagative values to cover reductions and error cases.
- smacro procedure get_action(state, terminal);
- << w1 := getv16(action_index, state);
- while not (((w2 := getv16(action_terminal, w1)) = -1) or
- w2 = terminal) do w1 := w1 + 1;
- getv(action_result, w1) >>;
- global '(action_first_error action_error_messages);
- global '(action_fn action_A action_n);
- symbolic procedure yyparse();
- begin
- scalar sym_stack, state_stack, next_input, w, w1, w2;
- state_stack := list 0; % Note that state 0 must be the initial one.
- start_parser();
- next_input := yylex();
- while not (w := get_action(car state_stack, next_input)) = 0 do
- if w > 0 then <<
- sym_stack := next_input . sym_stack;
- state_stack := cadr w . state_stack;
- next_input := yylex() >>
- else begin
- scalar A, n, action;
- w := - (w + 1);
- if w < action_first_error then <<
- action := getv(action_fn, w);
- n := getv8(action_n, w);
- A := getv16(action_A, w);
- % I am now reducing by "A -> beta { action() }" where beta has n items
- w := nil;
- for i := 1:n do <<
- w := car sym_stack . w;
- sym_stack := cdr sym_stack;
- state_stack := cdr state_stack >>;
- w := reversip w;
- if action then w := apply1(action, w)
- else w := A . w;
- sym_stack := w . sym_stack;
- state_stack := get_goto(car state_stack, A) >>
- else <<
- w := w - action_first_error;
- yyerror getv(action_error_messages, w);
- % The next activity must result in the loop ending...
- state_stack := list 0;
- sym_stack := '(error);
- next_input := 0 >>
- end;
- return car sym_stack
- end;
- %=============================================================================
- %
- % A grammar is represented as a list of rules. A rule
- % sym : x y z { p q r }
- % | x y z { p q r }
- % ;
- % maps onto the list
- % (sym ((x y z) p q r)
- % ((x y z) p q r))
- % and items on the right hand side can be symbols or strings. Strings
- % stand for terminals. Symbols that are mentioned on a left hand side of
- % a production are non-terminals, others are considered to be terminals
- % supported by the lexer.
- %
- % ***** I am still working out what to do with the "semantic actions".
- global '(terminals non_terminals symbols goto_cache action_map);
- smacro procedure lalr_productions x;
- get(x, 'produces);
- smacro procedure lalr_set_productions(x, y);
- put(x, 'produces, y);
- symbolic procedure lalr_prin_symbol x;
- if x = 0 then princ "$"
- else if x = nil then princ "<empty>"
- else if x = '!. then princ "."
- else if numberp x and rassoc(x, terminals) then
- prin car rassoc(x, terminals)
- else if stringp x then prin x
- else for each c in explode2uc x do princ c;
- symbolic procedure lalr_display_symbols();
- begin
- princ "Terminal symbols are:"; terpri();
- for each x in terminals do <<
- princ " "; prin car x;
- princ ":"; prin cdr x >>;
- terpri();
- princ "Non-terminal symbols are:"; terpri();
- for each x in non_terminals do begin
- scalar w;
- princ "["; prin get(x, 'non_terminal_code); princ "]";
- lalr_prin_symbol x;
- w := ":";
- for each y in lalr_productions x do <<
- ttab 20; princ w; w := "|";
- for each z in car y do << princ " "; lalr_prin_symbol z >>;
- if posn() > 48 then terpri();
- ttab 48;
- princ "{";
- for each z in cdr y do << princ " "; prin z >>;
- princ " }";
- terpri() >>;
- ttab 20;
- princ ";";
- terpri() end;
- terpri();
- end;
- symbolic procedure lalr_print_action_map();
- begin
- princ "Action map:"; terpri();
- for each x in action_map do <<
- prin cdr x; princ ":"; ttab 12; prin car x; terpri() >>
- end;
- symbolic procedure lalr_set_grammar g;
- begin
- scalar name, vals, tnum, w;
- terminals := non_terminals := symbols := nil;
- tnum := 0;
- % I will start by augmenting the grammar with an initial production...
- g := list('s!', list list caar g) . g;
- for each x in g do <<
- name := car x; vals := cdr x;
- if name member non_terminals then
- vals := append(vals, lalr_productions name)
- else non_terminals := name . non_terminals;
- for each vv in cdr x do
- for each v in car vv do <<
- if stringp v or numberp v then <<
- if not assoc(v, terminals) then
- terminals := (v . (tnum := tnum+1)) . terminals >>
- else if not (v member symbols) then symbols := v . symbols >>;
- lalr_set_productions(name, vals) >>;
- for each name in non_terminals do symbols := delete(name, symbols);
- for each v in symbols do terminals := (v . (tnum := tnum+1)) . terminals;
- % I reverse the list of non-terminals here so that the starting symbol
- % remains as the first item.
- non_terminals := reversip non_terminals;
- tnum := -1;
- for each v in non_terminals do
- put(v, 'non_terminal_code, tnum := tnum+1);
- symbols := append(non_terminals, for each x in terminals collect cdr x);
- goto_cache := mkhash(length non_terminals, 1, 1.5);
- if !*verbose then lalr_display_symbols();
- % Map all terminals onto numeric codes.
- for each x in non_terminals do
- lalr_set_productions(x,
- for each y in lalr_productions x collect
- sublis(terminals, car y) . cdr y);
- % Map all actions onto numeric codes, such that identical actions all have the
- % same code
- action_map := nil;
- tnum := -1;
- for each x in non_terminals do
- for each a in lalr_productions x do <<
- w := assoc(cdr a, action_map);
- if null w then <<
- w := cdr a . (tnum := tnum + 1);
- action_map := w . action_map >>;
- rplacd(a, list cdr w) >>;
- action_map := reversip action_map;
- if !*verbose then lalr_print_action_map();
- lalr_calculate_first non_terminals;
- end;
- symbolic procedure lalr_clean_up();
- begin
- for each x in terminals do <<
- remprop(x, 'produces);
- remprop(x, 'lalr_first);
- remprop(x, 'non_terminal_code) >>;
- terminals := non_terminals := symbols := nil;
- goto_cache := action_map := nil
- end;
- symbolic procedure lalr_action(lhs, rhs);
- cdr assoc(rhs, lalr_productions lhs);
- symbolic procedure lalr_print_firsts g;
- begin
- princ "FIRST sets for each non-terminal:"; terpri();
- for each x in g do <<
- lalr_prin_symbol x;
- princ ": ";
- ttab 15;
- for each y in get(x, 'lalr_first) do <<
- princ " "; lalr_prin_symbol y >>;
- terpri() >>
- end;
- symbolic procedure lalr_calculate_first g;
- begin
- scalar w, y, z, done;
- for each x in g do
- if assoc(nil, lalr_productions x) then put(x, 'lalr_first, '(nil));
- repeat <<
- done := nil;
- for each x in g do <<
- z := get(x, 'lalr_first);
- for each y1 in lalr_productions x do <<
- y := car y1;
- while y and
- not numberp y
- and (nil member (w := get(car y, 'lalr_first))) do <<
- z := union(w, z);
- y := cdr y >>;
- if null y then nil
- else if numberp car y then z := union(list car y, z)
- else z := union(get(car y, 'lalr_first), z) >>;
- if not (z = get(x, 'lalr_first)) then done := t;
- put(x, 'lalr_first, z) >>
- >> until not done;
- if !*verbose then lalr_print_firsts g;
- return nil
- end;
- symbolic procedure lalr_first l;
- begin
- scalar r, w;
- while l and
- not numberp car l and
- (nil member (w := get(car l, 'lalr_first))) do <<
- r := union(delete(nil, w), r);
- l := cdr l >>;
- if null l then r := nil . r
- else if numberp car l then r := union(list car l, r)
- else r := union(w, r);
- return r
- end;
- % The next few procedures are as documented in Figure 4.38 of Red Dragon
- symbolic procedure lalr_print_items(heading, cc);
- begin
- princ heading;
- terpri();
- for each y in cc do <<
- princ "Item number "; prin cdr y; terpri();
- for each x in sort(car y, function orderp) do <<
- lalr_prin_symbol caar x; princ " ->";
- for each y in cdar x do << princ " "; lalr_prin_symbol y >>;
- princ " : ";
- lalr_prin_symbol cadr x;
- terpri() >>;
- for each x in hashcontents goto_cache do
- for each xx in cdr x do
- if car xx = cdr y then <<
- ttab 10; lalr_prin_symbol car x;
- princ " GOTO state "; prin cdr xx; terpri() >> >>
- end;
- symbolic procedure lalr_items g;
- begin
- scalar c, val, done, w, w1, w2, n;
- val := lalr_productions 's!';
- if cdr val then error(0, "Starting state must only reduce to one thing")
- else val := caar val;
- n := 0;
- c := list (lalr_closure list list(('s!' . '!. . val), 0) . n);
- repeat <<
- done := nil;
- for each i in c do
- for each x in symbols do
- if w := lalr_goto(car i, x) then <<
- w1 := assoc(w, c);
- if w1 then <<
- w2 := gethash(x, goto_cache);
- if not assoc(cdr i, w2) then
- puthash(x, goto_cache, (cdr i . cdr w1) . w2) >>
- else <<
- c := (w . (n := n + 1)) . c;
- puthash(x, goto_cache,
- (cdr i . n) . gethash(x, goto_cache));
- done := t >> >>
- >> until not done;
- c := reversip c; % So that item numbers come out in nicer order.
- if !*verbose then lalr_print_items("LR(1) Items:", c);
- return c
- end;
- symbolic procedure lalr_closure i;
- begin
- scalar pending, a, rule, tail, done, ff, w;
- pending := i;
- while pending do <<
- ff := car pending; % [(A -> alpha . B beta), a]
- pending := cdr pending;
- rule := car ff; a := cadr ff; tail := cdr ('!. member rule);
- if tail and not numberp car tail then <<
- ff := lalr_first append(cdr tail, list a);
- for each p in lalr_productions car tail do
- for each b in ff do <<
- w := list(car tail . '!. . car p, b);
- % It might be better to store items as hash tables, since then the
- % member-check here would be much faster.
- if not (w member i) then <<
- i := w . i;
- pending := w . pending >> >> >> >>;
- return i
- end;
- symbolic procedure lalr_move_dot(z, x);
- begin
- scalar r;
- while not (car z = '!.) do <<
- r := car z . r;
- z := cdr z >>;
- z := cdr z;
- if not (z and car z = x) then return nil;
- z := car z . '!. . cdr z;
- while r do <<
- z := car r . z;
- r := cdr r >>;
- return z
- end;
- symbolic procedure lalr_goto(i, x);
- begin
- scalar j, w;
- for each z in i do <<
- w := lalr_move_dot(car z, x);
- if w then j := list(w, cadr z) . j >>;
- return lalr_closure j
- end;
- symbolic procedure lalr_cached_goto(i, x);
- cdr assoc(i, gethash(x, goto_cache));
- % Next part of Algorithm 4.11 from the Red Dragon
- symbolic procedure lalr_remove_duplicates x;
- begin
- scalar r;
- if null x then return nil;
- x := sort(x, function orderp);
- r := list car x;
- x := cdr x;
- while x do <<
- if not (car x = car r) then r := car x . r;
- x := cdr x >>;
- return r
- end;
- symbolic procedure lalr_core i;
- lalr_remove_duplicates for each x in car i collect car x;
- symbolic procedure lalr_same_core(i1, i2);
- lalr_core i1 = lalr_core i2;
- % cc is a list of items, while i is a single item. If cc already contains
- % an item with the same core as I then merge i into that, and adjust any
- % goto records either out of or into i to refer now to the thing merged
- % with.
- fluid '(renamings);
- symbolic procedure lalr_insert_core(i, cc);
- if null cc then list i
- else if lalr_same_core(i, car cc) then <<
- renamings := (i . cdar cc) . renamings;
- (union(car i, caar cc) . cdar cc) . cdr cc >>
- else car cc . lalr_insert_core(i, cdr cc);
- symbolic procedure lalr_rename_gotos();
- begin
- scalar w;
- for each x in non_terminals do <<
- w := sublis(renamings, gethash(x, goto_cache));
- puthash(x, goto_cache, lalr_remove_duplicates w) >>
- end;
- % Part of Algorithm 4.10 of the Red Dragon
- symbolic procedure lalr_print_actions action_table;
- begin
- scalar w;
- princ "Actions:"; terpri();
- for each x in action_table do
- for each xx in cdr x do <<
- prin car x; ttab 20;
- lalr_prin_symbol car xx; ttab 40;
- w := cadr xx;
- if eqcar(w, 'reduce) then <<
- princ "reduce ";
- lalr_prin_symbol caadr w;
- princ " ->";
- for each v in cdadr w do << princ " "; lalr_prin_symbol v >>;
- princ " {";
- for each v in caddr w do << princ " "; prin v >>;
- princ " }";
- terpri() >>
- else << prin w; terpri() >> >>
- end;
- symbolic procedure lalr_make_actions c;
- begin
- scalar action_table, aa, j, w;
- for each i in c do <<
- aa := nil;
- for each r in car i do <<
- w := cdr ('!. member cdar r);
- if w and numberp car w then <<
- j := lalr_cached_goto(cdr i, car w);
- aa := list(car w, list('shift, j)) . aa >>
- else if null w and not (caar r = 's!') then <<
- w := reverse cdr reverse car r;
- aa :=
- list(cadr r, list('reduce, w, lalr_action(car w, cdr w))) .
- aa >>
- else if null w and caar r = 's!' then
- aa := list(0, 'accept) . aa >>;
- action_table := (cdr i . lalr_remove_duplicates aa) . action_table >>;
- action_index := mkvect16 caar action_table;
- action_table := reversip action_table;
- if !*verbose then lalr_print_actions action_table;
- j := 0; w := nil;
- for each x in action_table do <<
- putv16(action_index, car x, j);
- aa := lalr_lay_out_actions cdr x;
- while aa do <<
- w := (0 . 0) . w;
- j := j + 1 >> >>;
- action_terminal := mkvect16 j;
- action_result := mkvect16 j;
- while j > 0 do <<
- j := j - 1;
- putv16(action_terminal, j, caar w);
- putv16(action_result, j, cdar w);
- w := cdr w >>
- end;
- symbolic procedure lalr_most_common_dest p;
- begin
- scalar r, w;
- for each x in p do
- if (w := assoc(cdr x, r)) then rplacd(w, cdr w + 1)
- else r := (cdr x . 1) . r;
- w := car r;
- for each x in cdr r do if cdr x > cdr w then w := x;
- return car w
- end;
- symbolic procedure lalr_make_gotos();
- begin
- scalar p, r1, w, r;
- p := 0;
- for each x in hashcontents goto_cache do
- if not numberp car x then <<
- if !*verbose then
- for each xx in cdr x do <<
- prin car xx; ttab 10; lalr_prin_symbol car x;
- princ " GOTO state "; prin cdr xx; terpri() >>;
- r1 := (get(car x, 'non_terminal_code) . p) . r1;
- if cdr x then <<
- w := lalr_most_common_dest cdr x;
- for each xx in cdr x do if not (cdr xx = w) then <<
- r := xx . r;
- p := p + 1 >>;
- r := ((-1) . w) . r;
- p := p + 1 >> >>;
- goto_index := mkvect16 length non_terminals;
- goto_old_state := mkvect16 p;
- goto_new_state := mkvect16 p;
- for each x in r1 do putv16(goto_index, car x, cdr x);
- while p > 0 do <<
- p := p - 1;
- putv16(goto_old_state, p, caar r);
- putv16(goto_new_state, p, cdar r);
- r := cdr r >>;
- princ "goto_index: "; print goto_index;
- princ "goto_old_state: "; print goto_old_state;
- princ "goto_new_state: "; print goto_new_state
- end;
- % A main driver function that performs all the steps involved
- % in building parse tables for a given grammar.
- symbolic procedure lalr_construct_parser g;
- begin
- scalar c, cc, renamings;
- lalr_set_grammar g;
- c := lalr_items non_terminals;
- renamings := nil;
- for each i in c do cc := lalr_insert_core(i, cc);
- lalr_rename_gotos();
- if !*verbose then lalr_print_items("Merged Items:", cc);
- lalr_make_actions cc;
- lalr_make_gotos();
- lalr_clean_up()
- end;
- %=============================================================================
- % Now some test cases
- on time;
- % Here I set up a sample grammar
- % S' -> S
- % S -> CC { A1 }
- % C -> cC { A2 }
- % | d { A3 }
- % (example 4.42 from Aho, Sethi and Ullman's Red Dragon book, with
- % some dummy semantic actions added. Note that I do not need to insert
- % the production S' -> S for myself since the analysis code will
- % augment my grammar with it for me anyway.
- grammar := '((S ((C C) A1))
- (C (("c" C) A2)
- (("d") A3))
- );
- lalr_construct_parser grammar;
- % Example 4.46 from the Red Dragon
- g4_46 := '((S ((L "=" R) a1)
- ((R) a2))
- (L (("*" R) a3)
- ((id) a4))
- (R ((L) a5)));
- lalr_construct_parser g4_46;
- % Now a much more complicated grammar - one that recognizes the syntax of
- % RLISP.
- rlisp_grammar := '(
- (command (( cmnd sep ) action)
- (( end sep ) action)
- (( command cmnd sep ) action)
- (( command end sep ) action)
- )
- (sep (( ";" ) action)
- (( "$" ) action)
- )
- (proc_type (( symbolic ) action)
- (( algebraic ) action)
- )
- (proc_qual (( expr ) action)
- (( macro ) action)
- (( smacro ) action)
- )
- (sym_list (( ")" ) action)
- (( "," symbol sym_list ) action)
- )
- (infix (( setq ) action)
- (( or ) action)
- (( and ) action)
- (( member ) action)
- (( memq ) action)
- (( "=" ) action)
- (( neq ) action)
- (( eq ) action)
- (( geq ) action)
- (( ">" ) action)
- (( leq ) action)
- (( "<" ) action)
- (( freeof ) action)
- (( "+" ) action)
- (( "-" ) action)
- (( "*" ) action)
- (( "/" ) action)
- (( "^" ) action)
- (( "." ) action)
- )
- (prefix (( not ) action)
- (( "+" ) action)
- (( "-" ) action)
- )
- (proc_head (( symbol ) action)
- (( symbol symbol ) action)
- (( symbol "(" ")" ) action)
- (( symbol "(" symbol sym_list ) action)
- (( prefix symbol ) action)
- (( symbol infix symbol ) action)
- )
- (proc_def (( procedure proc_head sep cmnd ) action)
- (( proc_type procedure proc_head sep cmnd ) action)
- (( proc_qual procedure proc_head sep cmnd ) action)
- (( proc_type proc_qual procedure proc_head sep cmnd ) action)
- )
- (rlistat (( rlistat ) action)
- (( in ) action)
- (( on ) action)
- )
- (rltail (( expr ) action)
- (( expr "," rltail ) action)
- )
- (cmnd (( expr ) action)
- (( rlistat rltail ) action)
- )
- (if_stmt (( if expr then cmnd else cmnd ) action)
- (( if expr then cmnd ) action)
- )
- (for_update (( ":" expr ) action)
- (( step expr until expr ) action)
- )
- (for_action (( do ) action)
- (( sum ) action)
- (( collect ) action)
- )
- (for_inon (( in ) action)
- (( on ) action)
- )
- (for_stmt (( for symbol setq expr for_update for_action cmnd ) action)
- (( for each symbol for_inon expr for_action cmnd ) action)
- (( foreach symbol for_inon expr for_action cmnd ) action)
- )
- (while_stmt (( while expr do cmnd ) action)
- )
- (repeat_stmt (( repeat cmnd until expr ) action)
- )
- (return_stmt (( return ) action)
- (( return expr ) action)
- )
- (goto_stmt (( goto symbol ) action)
- (( go symbol ) action)
- (( go to symbol ) action)
- )
- (group_tail (( rsect ) action)
- (( sep rsect ) action)
- (( sep cmnd group_tail ) action)
- )
- (group_expr (( lsect cmnd group_tail ) action)
- )
- (scalar_tail (( sep ) action)
- (( "," symbol scalar_tail ) action)
- (( "," integer scalar_tail ) action)
- )
- (scalar_def (( scalar symbol scalar_tail ) action)
- (( integer symbol scalar_tail ) action)
- )
- (scalar_defs (( scalar_def ) action)
- (( scalar_defs scalar_def ) action)
- )
- (block_tail (( end ) action)
- (( cmnd end ) action)
- (( symbol ":" block_tail ) action)
- (( cmnd sep block_tail ) action)
- (( sep block_tail ) action)
- )
- (block_expr (( begin scalar_defs block_tail ) action)
- (( begin block_tail ) action)
- )
- (lambda_vars (( sep ) action)
- (( "," symbol lambda_vars ) action)
- )
- (lambda_expr (( lambda symbol lambda_vars cmnd ) action)
- (( lambda "(" ")" sep cmnd ) action)
- (( lambda "(" symbol sym_list sep cmnd ) action)
- )
- (expr (( rx0 ) action)
- (( lx0 ) action)
- )
- (rx0 (( lx0 where symbol "=" rx1 ) action)
- (( rx1 ) action)
- )
- (lx0 (( lx0 where symbol "=" lx1 ) action)
- (( lx1 ) action)
- )
- (rx1 (( lx2 setq rx1 ) action)
- (( rx2 ) action)
- )
- (lx1 (( lx2 setq lx1 ) action)
- (( lx2 ) action)
- )
- (rx2tail (( rx3 ) action)
- (( lx3 or rx2tail ) action)
- )
- (rx2 (( lx3 or rx2tail ) action)
- (( rx3 ) action)
- )
- (lx2tail (( lx3 ) action)
- (( lx3 or lx2tail ) action)
- )
- (lx2 (( lx3 or lx2tail ) action)
- (( lx3 ) action)
- )
- (rx3tail (( rx4 ) action)
- (( lx4 and rx3tail ) action)
- )
- (rx3 (( lx4 and rx3tail ) action)
- (( rx4 ) action)
- )
- (lx3tail (( lx4 ) action)
- (( lx4 and lx3tail ) action)
- )
- (lx3 (( lx4 and lx3tail ) action)
- (( lx4 ) action)
- )
- (rx4 (( not rx4 ) action)
- (( rx5 ) action)
- )
- (lx4 (( not lx4 ) action)
- (( lx5 ) action)
- )
- (rx5 (( lx6 member ry6 ) action)
- (( lx6 memq ry6 ) action)
- (( lx6 "=" ry6 ) action)
- (( lx6 neq ry6 ) action)
- (( lx6 eq ry6 ) action)
- (( lx6 geq ry6 ) action)
- (( lx6 ">" ry6 ) action)
- (( lx6 leq ry6 ) action)
- (( lx6 "<" ry6 ) action)
- (( lx6 freeof ry6 ) action)
- (( rx6 ) action)
- )
- (lx5 (( lx6 member ly6 ) action)
- (( lx6 memq ly6 ) action)
- (( lx6 "=" ly6 ) action)
- (( lx6 neq ly6 ) action)
- (( lx6 eq ly6 ) action)
- (( lx6 geq ly6 ) action)
- (( lx6 ">" ly6 ) action)
- (( lx6 leq ly6 ) action)
- (( lx6 "<" ly6 ) action)
- (( lx6 freeof ly6 ) action)
- (( lx6 ) action)
- )
- (ry6 (( not ry6 ) action)
- (( rx6 ) action)
- )
- (ly6 (( not ly6 ) action)
- (( lx6 ) action)
- )
- (rx6tail (( ry6a ) action)
- (( ly6a "+" rx6tail ) action)
- )
- (rx6 (( lx6a "+" rx6tail ) action)
- (( rx6a ) action)
- )
- (lx6tail (( ly6a ) action)
- (( ly6a "+" lx6tail ) action)
- )
- (lx6 (( lx6a "+" lx6tail ) action)
- (( lx6a ) action)
- )
- (ry6a (( not ry6a ) action)
- (( rx6a ) action)
- )
- (rx6a (( lx6a "-" ry7 ) action)
- (( rx7 ) action)
- )
- (ly6a (( not ly6a ) action)
- (( lx6a ) action)
- )
- (lx6a (( lx6a "-" ly7 ) action)
- (( lx7 ) action)
- )
- (ry7 (( not ry7 ) action)
- (( rx7 ) action)
- )
- (rx7 (( "+" ry7 ) action)
- (( "-" ry7 ) action)
- (( rx8 ) action)
- )
- (ly7 (( not ly7 ) action)
- (( lx7 ) action)
- )
- (lx7 (( "+" ly7 ) action)
- (( "-" ly7 ) action)
- (( lx8 ) action)
- )
- (rx8tail (( ry9 ) action)
- (( ly9 "*" rx8tail ) action)
- )
- (rx8 (( lx9 "*" rx8tail ) action)
- (( rx9 ) action)
- )
- (lx8tail (( ly9 ) action)
- (( ly9 "*" lx8tail ) action)
- )
- (lx8 (( lx9 "*" lx8tail ) action)
- (( lx9 ) action)
- )
- (ry9 (( not ry9 ) action)
- (( "+" ry9 ) action)
- (( "-" ry9 ) action)
- (( rx9 ) action)
- )
- (rx9 (( lx9 "/" ry10 ) action)
- (( rx10 ) action)
- )
- (ly9 (( not ly9 ) action)
- (( "+" ly9 ) action)
- (( "-" ly9 ) action)
- (( lx9 ) action)
- )
- (lx9 (( lx9 "/" ly10 ) action)
- (( lx10 ) action)
- )
- (ly10 (( not ly10 ) action)
- (( "+" ly10 ) action)
- (( "-" ly10 ) action)
- (( lx10 ) action)
- )
- (lx10 (( lx11 "^" ly10 ) action)
- (( lx11 ) action)
- )
- (ry10 (( not ry10 ) action)
- (( "+" ry10 ) action)
- (( "-" ry10 ) action)
- (( rx10 ) action)
- )
- (rx10 (( lx11 "^" ry10 ) action)
- (( rx11 ) action)
- )
- (ry11 (( not ry11 ) action)
- (( "+" ry11 ) action)
- (( "-" ry11 ) action)
- (( rx11 ) action)
- )
- (rx11 (( x12 "." ry11 ) action)
- (( if_stmt ) action)
- (( for_stmt ) action)
- (( while_stmt ) action)
- (( repeat_stmt ) action)
- (( return_stmt ) action)
- (( goto_stmt ) action)
- (( lambda_expr ) action)
- (( proc_type ) action)
- (( proc_def ) action)
- (( endstat ) action)
- )
- (ly11 (( not ly11 ) action)
- (( "+" ly11 ) action)
- (( "-" ly11 ) action)
- (( lx11 ) action)
- )
- (lx11 (( x12 "." ly11 ) action)
- (( x12 ) action)
- )
- (arg_list (( expr ")" ) action)
- (( expr "," arg_list ) action)
- )
- (x12 (( x13 "[" expr "]" ) action)
- (( x13 "(" ")" ) action)
- (( x13 "(" expr "," arg_list ) action)
- (( x13 x12 ) action)
- (( x13 ) action)
- )
- (x13 (( symbol ) action)
- (( number ) action)
- (( string ) action)
- (( quoted ) action)
- (( backquoted ) action)
- (( group_expr ) action)
- (( block_expr ) action)
- (( "(" expr ")" ) action)
- )
- )$
- % lalr_construct_parser rlisp_grammar;
- end;
|