123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- {
- Semantic routines for the Yacc parser.
- Copyright (c) 1990-92 Albert Graef <[email protected]>
- Copyright (C) 1996 Berend de Boer <[email protected]>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Revision: 1.2 $
- $Modtime: 96-08-01 6:03 $
- $History: YACCSEM.PAS $
- *
- * ***************** Version 2 *****************
- * User: Berend Date: 96-10-10 Time: 21:16
- * Updated in $/Lex and Yacc/tply
- * Updated for protected mode, windows and Delphi 1.X and 2.X.
- }
- unit YaccSem;
- interface
- var
- act_prec : Integer;
- (* active precedence level in token and precedence declarations (0 in
- %token declaration) *)
- act_type : Integer;
- (* active type tag in token, precedence and type declarations *)
- procedure yyerror ( msg : String );
- (* YaccLib.yyerror redefined to ignore 'syntax error' message; the parser
- does its own error handling *)
- function sym ( k : Integer ) : Integer;
- (* returns internal symbol number for the symbol k; if k is yet undefined,
- a new nonterminal or literal symbol is created, according to the
- appearance of symbol k (nonterminal if an ordinary identifier, literal
- otherwise) *)
- function ntsym ( k : Integer ) : Integer;
- (* like sym, but requires symbol k to be a nonterminal symbol; if it
- is already defined a literal, an error message is issued, and a dummy
- nonterminal symbol returned *)
- function litsym ( k : Integer; n : Integer ) : Integer;
- (* same for literal symbols; if n>0 it denotes the literal number to be
- assigned to the symbol; when a new literal identifier is defined, a
- corresponding constant definition is also written to the definition
- file *)
- procedure next_section;
- (* find next section mark (%%) in code template *)
- procedure definitions;
- (* if necessary, write out definition of the semantic value type YYSType *)
- procedure copy_code;
- (* copy Turbo Pascal code section ( %{ ... %} ) to output file *)
- procedure copy_action;
- (* copy an action to the output file *)
- procedure copy_single_action;
- (* like copy_action, but action must be single statement terminated
- with `;' *)
- procedure copy_rest_of_file;
- (* copies the rest of the source file to the output file *)
- procedure start_rule ( sym : Integer );
- (* start a new rule with lhs nonterminal symbol sym *)
- procedure start_body;
- (* start a new rule body (rhs) *)
- procedure end_body;
- (* end a rule body *)
- procedure add_symbol ( sym : Integer );
- (* add the denoted symbol to the current rule body *)
- procedure add_action;
- (* add an action to the current rule body *)
- procedure add_rule_prec ( sym : Integer );
- (* add the precedence of terminal symbol sym to the current rule *)
- procedure generate_parser;
- (* generate the parse table *)
- implementation
- uses YaccBase, YaccTabl, YaccClos, YaccLR0, YaccLook,
- YaccPars, YaccMsgs;
- procedure yyerror ( msg : String );
- begin
- if msg='syntax error' then
- (* ignore *)
- else
- fatal(msg)
- end(*yyerror*);
- function act_char : char;
- begin
- if cno>length(line) then
- if eof(yyin) then
- act_char := #0
- else
- act_char := nl
- else
- act_char := line[cno]
- end(*act_char*);
- function lookahead_char : char;
- begin
- if succ(cno)>length(line) then
- if eof(yyin) then
- lookahead_char := #0
- else
- lookahead_char := nl
- else
- lookahead_char := line[succ(cno)]
- end(*lookahead_char*);
- procedure next_char;
- begin
- if cno>length(line) then
- if eof(yyin) then
- { nop }
- else
- begin
- readln(yyin, line);
- inc(lno); cno := 1
- end
- else
- inc(cno)
- end(*next_char*);
- var
- (* Current rule: *)
- act_rule : RuleRec;
- (* Actions: *)
- n_act : Integer;
- p_act : Boolean;
- function sym ( k : Integer ) : Integer;
- var s : Integer;
- begin
- if is_def_key(k, s) then
- sym := s
- else if sym_table^[k].pname^[1]='''' then
- begin
- s := new_lit;
- def_key(k, s);
- sym := s;
- end
- else
- begin
- s := new_nt;
- def_key(k, s);
- sym := s;
- end
- end(*sym*);
- function ntsym ( k : Integer ) : Integer;
- var s : Integer;
- begin
- if is_def_key(k, s) then
- if s<0 then
- ntsym := s
- else
- begin
- error(nonterm_expected);
- ntsym := -1;
- end
- else if sym_table^[k].pname^[1]='''' then
- begin
- error(nonterm_expected);
- ntsym := -1;
- end
- else
- begin
- s := new_nt;
- def_key(k, s);
- ntsym := s;
- end
- end(*ntsym*);
- function litsym ( k : Integer; n : Integer ) : Integer;
- var s : Integer;
- begin
- if is_def_key(k, s) then
- if s>=0 then
- begin
- if n>0 then error(double_tokennum_def);
- litsym := s;
- end
- else
- begin
- error(literal_expected);
- litsym := 1;
- end
- else if sym_table^[k].pname^[1]='''' then
- begin
- if n>0 then
- begin
- add_lit(n);
- s := n;
- end
- else
- s := new_lit;
- def_key(k, s);
- litsym := s;
- end
- else
- begin
- if n>0 then
- begin
- add_lit(n);
- s := n;
- end
- else
- s := new_lit;
- def_key(k, s);
- writeln(yyout, 'const ', pname(s), ' = ', s, ';');
- litsym := s;
- end;
- end(*litsym*);
- procedure next_section;
- var line : String;
- begin
- while not eof(yycod) do
- begin
- readln(yycod, line);
- if line='%%' then exit;
- writeln(yyout, line);
- end;
- end(*next_section*);
- procedure definitions;
- var i : Integer;
- begin
- if n_types>0 then
- begin
- writeln(yyout);
- writeln(yyout, 'type YYSType = record case Integer of');
- for i := 1 to n_types do
- writeln(yyout, ' ':15, i:3, ' : ( ',
- 'yy', sym_table^[type_table^[i]].pname^, ' : ',
- sym_table^[type_table^[i]].pname^, ' );');
- writeln(yyout, ' ':15, 'end(*YYSType*);');
- end;
- end(*definitions*);
- procedure copy_code;
- var str_state : Boolean;
- begin
- str_state := false;
- while act_char<>#0 do
- if act_char=nl then
- begin
- writeln(yyout);
- next_char;
- end
- else if act_char='''' then
- begin
- write(yyout, '''');
- str_state := not str_state;
- next_char;
- end
- else if not str_state and (act_char='%') and (lookahead_char='}') then
- exit
- else
- begin
- write(yyout, act_char);
- next_char;
- end;
- end(*copy_code*);
- procedure scan_val;
- (* process a $ value in an action
- (not very pretty, but it does its job) *)
- var tag, numstr : String; i, code : Integer;
- begin
- tokleng := 0;
- next_char;
- if act_char='<' then
- begin
- (* process type tag: *)
- next_char;
- tag := '';
- while (act_char<>nl) and (act_char<>#0) and (act_char<>'>') do
- begin
- tag := tag+act_char;
- next_char;
- end;
- if act_char='>' then
- begin
- if not search_type(tag) then
- begin
- tokleng := length(tag);
- error(unknown_identifier);
- end;
- next_char;
- end
- else
- error(syntax_error);
- end
- else
- tag := '';
- tokleng := 0;
- if act_char='$' then
- begin
- (* left-hand side value: *)
- write(yyout, 'yyval');
- (* check for value type: *)
- if (tag='') and (n_types>0) then with act_rule do
- if sym_type^[lhs_sym]>0 then
- tag := sym_table^[sym_type^[lhs_sym]].pname^
- else
- begin
- tokleng := 1;
- error(type_error);
- end;
- if tag<>'' then write(yyout, '.yy', tag);
- next_char;
- end
- else
- begin
- (* right-hand side value: *)
- if act_char='-' then
- begin
- numstr := '-';
- next_char;
- end
- else
- numstr := '';
- while ('0'<=act_char) and (act_char<='9') do
- begin
- numstr := numstr+act_char;
- next_char;
- end;
- if numstr<>'' then
- begin
- val(numstr, i, code);
- if code=0 then
- if i<=act_rule.rhs_len then
- begin
- write(yyout, 'yyv[yysp-', act_rule.rhs_len-i, ']');
- (* check for value type: *)
- if (tag='') and (n_types>0) then with act_rule do
- if i<=0 then
- begin
- tokleng := length(numstr)+1;
- error(type_error);
- end
- else if sym_type^[rhs_sym[i]]>0 then
- tag := sym_table^[sym_type^[rhs_sym[i]]].pname^
- else
- begin
- tokleng := length(numstr)+1;
- error(type_error);
- end;
- if tag<>'' then write(yyout, '.yy', tag);
- end
- else
- begin
- tokleng := length(numstr);
- error(range_error);
- end
- else
- error(syntax_error)
- end
- else
- error(syntax_error)
- end
- end(*scan_val*);
- procedure copy_action;
- var str_state : Boolean;
- begin
- str_state := false;
- while act_char=' ' do next_char;
- write(yyout, ' ':9);
- while act_char<>#0 do
- if act_char=nl then
- begin
- writeln(yyout);
- next_char;
- while act_char=' ' do next_char;
- write(yyout, ' ':9);
- end
- else if act_char='''' then
- begin
- write(yyout, '''');
- str_state := not str_state;
- next_char;
- end
- else if not str_state and (act_char='}') then
- begin
- writeln(yyout);
- exit;
- end
- else if not str_state and (act_char='$') then
- scan_val
- else
- begin
- write(yyout, act_char);
- next_char;
- end;
- end(*copy_action*);
- procedure copy_single_action;
- var str_state : Boolean;
- begin
- str_state := false;
- while act_char=' ' do next_char;
- write(yyout, ' ':9);
- while act_char<>#0 do
- if act_char=nl then
- begin
- writeln(yyout);
- next_char;
- while act_char=' ' do next_char;
- write(yyout, ' ':9);
- end
- else if act_char='''' then
- begin
- write(yyout, '''');
- str_state := not str_state;
- next_char;
- end
- else if not str_state and (act_char=';') then
- begin
- writeln(yyout, ';');
- exit;
- end
- else if not str_state and (act_char='$') then
- scan_val
- else
- begin
- write(yyout, act_char);
- next_char;
- end;
- end(*copy_single_action*);
- procedure copy_rest_of_file;
- begin
- while act_char<>#0 do
- if act_char=nl then
- begin
- writeln(yyout);
- next_char;
- end
- else
- begin
- write(yyout, act_char);
- next_char;
- end;
- end(*copy_rest_of_file*);
- procedure start_rule ( sym : Integer );
- begin
- if n_rules=0 then
- begin
- (* fix start nonterminal of the grammar: *)
- if startnt=0 then startnt := sym;
- (* add augmented start production: *)
- with act_rule do
- begin
- lhs_sym := -1;
- rhs_len := 2;
- rhs_sym[1] := startnt;
- rhs_sym[2] := 0; (* end marker *)
- end;
- add_rule(newRuleRec(act_rule));
- end;
- act_rule.lhs_sym := sym;
- end(*start_rule*);
- procedure start_body;
- begin
- act_rule.rhs_len := 0;
- p_act := false;
- writeln(yyout, n_rules:4, ' : begin');
- end(*start_body*);
- procedure end_body;
- begin
- if not p_act and (act_rule.rhs_len>0) then
- (* add default action: *)
- writeln(yyout, ' ':9, 'yyval := yyv[yysp-',
- act_rule.rhs_len-1, '];');
- add_rule(newRuleRec(act_rule));
- writeln(yyout, ' ':7, 'end;');
- end(*end_body*);
- procedure add_rule_action;
- (* process an action inside a rule *)
- var k : Integer; r : RuleRec;
- begin
- writeln(yyout, ' ':7, 'end;');
- inc(n_act);
- k := get_key('$$'+intStr(n_act));
- with r do
- begin
- lhs_sym := new_nt;
- def_key(k, lhs_sym);
- rhs_len := 0;
- end;
- with act_rule do
- begin
- inc(rhs_len);
- if rhs_len>max_rule_len then fatal(rule_table_overflow);
- rhs_sym[rhs_len] := r.lhs_sym;
- end;
- add_rule(newRuleRec(r));
- rule_prec^[n_rules+1] := rule_prec^[n_rules];
- rule_prec^[n_rules] := 0;
- writeln(yyout, n_rules:4, ' : begin');
- end(*add_rule_action*);
- procedure add_symbol ( sym : Integer );
- begin
- if p_act then add_rule_action;
- p_act := false;
- with act_rule do
- begin
- inc(rhs_len);
- if rhs_len>max_rule_len then fatal(rule_table_overflow);
- rhs_sym[rhs_len] := sym;
- if sym>=0 then rule_prec^[n_rules+1] := sym_prec^[sym]
- end
- end(*add_symbol*);
- procedure add_action;
- begin
- if p_act then add_rule_action;
- p_act := true;
- end(*add_action*);
- procedure add_rule_prec ( sym : Integer );
- begin
- rule_prec^[n_rules+1] := sym_prec^[sym];
- end(*add_rule_prec*);
- procedure generate_parser;
- begin
- if startnt=0 then error(empty_grammar);
- if errors=0 then
- begin
- write('sort ... ');
- sort_rules; rule_offsets;
- write('closures ... ');
- closures;
- write('first sets ... ');
- first_sets;
- write('LR0 set ... ');
- LR0Set;
- write('lookaheads ... ');
- lookaheads;
- writeln;
- write('code generation ... ');
- parse_table;
- end;
- end(*generate_parser*);
- begin
- n_act := 0;
- end(*YaccSem*).
|