📄 yacc.pas
字号:
{ 79: } ( len: 0; sym: -50 ),
{ 80: } ( len: 6; sym: -43 ),
{ 81: } ( len: 1; sym: -47 ),
{ 82: } ( len: 0; sym: -52 ),
{ 83: } ( len: 4; sym: -47 ),
{ 84: } ( len: 0; sym: -49 ),
{ 85: } ( len: 2; sym: -49 ),
{ 86: } ( len: 2; sym: -49 ),
{ 87: } ( len: 2; sym: -49 ),
{ 88: } ( len: 2; sym: -49 ),
{ 89: } ( len: 2; sym: -49 ),
{ 90: } ( len: 0; sym: -54 ),
{ 91: } ( len: 3; sym: -53 ),
{ 92: } ( len: 1; sym: -53 ),
{ 93: } ( len: 0; sym: -51 ),
{ 94: } ( len: 0; sym: -56 ),
{ 95: } ( len: 4; sym: -51 ),
{ 96: } ( len: 0; sym: -57 ),
{ 97: } ( len: 4; sym: -51 ),
{ 98: } ( len: 0; sym: -58 ),
{ 99: } ( len: 4; sym: -51 ),
{ 100: } ( len: 2; sym: -51 ),
{ 101: } ( len: 0; sym: -55 ),
{ 102: } ( len: 1; sym: -55 )
);
const _error = 256; (* error token *)
function yyact(state, sym : Integer; var act : Integer) : Boolean;
(* search action table *)
var k : Integer;
begin
k := yyal[state];
while (k<=yyah[state]) and (yya[k].sym<>sym) do inc(k);
if k>yyah[state] then
yyact := false
else
begin
act := yya[k].act;
yyact := true;
end;
end(*yyact*);
function yygoto(state, sym : Integer; var nstate : Integer) : Boolean;
(* search goto table *)
var k : Integer;
begin
k := yygl[state];
while (k<=yygh[state]) and (yyg[k].sym<>sym) do inc(k);
if k>yygh[state] then
yygoto := false
else
begin
nstate := yyg[k].act;
yygoto := true;
end;
end(*yygoto*);
label parse, next, error, errlab, shift, reduce, accept, abort;
begin(*yyparse*)
(* initialize: *)
yystate := 0; yychar := -1; yynerrs := 0; yyerrflag := 0; yysp := 0;
{$ifdef yydebug}
yydebug := true;
{$else}
yydebug := false;
{$endif}
parse:
(* push state and value: *)
inc(yysp);
if yysp>yymaxdepth then
begin
yyerror('yyparse stack overflow');
goto abort;
end;
yys[yysp] := yystate; yyv[yysp] := yyval;
next:
if (yyd[yystate]=0) and (yychar=-1) then
(* get next symbol *)
begin
yychar := yylex; if yychar<0 then yychar := 0;
end;
if yydebug then writeln('state ', yystate, ', char ', yychar);
(* determine parse action: *)
yyn := yyd[yystate];
if yyn<>0 then goto reduce; (* simple state *)
(* no default action; search parse table *)
if not yyact(yystate, yychar, yyn) then goto error
else if yyn>0 then goto shift
else if yyn<0 then goto reduce
else goto accept;
error:
(* error; start error recovery: *)
if yyerrflag=0 then yyerror('syntax error');
errlab:
if yyerrflag=0 then inc(yynerrs); (* new error *)
if yyerrflag<=2 then (* incomplete recovery; try again *)
begin
yyerrflag := 3;
(* uncover a state with shift action on error token *)
while (yysp>0) and not ( yyact(yys[yysp], _error, yyn) and
(yyn>0) ) do
begin
if yydebug then
if yysp>1 then
writeln('error recovery pops state ', yys[yysp], ', uncovers ',
yys[yysp-1])
else
writeln('error recovery fails ... abort');
dec(yysp);
end;
if yysp=0 then goto abort; (* parser has fallen from stack; abort *)
yystate := yyn; (* simulate shift on error *)
goto parse;
end
else (* no shift yet; discard symbol *)
begin
if yydebug then writeln('error recovery discards char ', yychar);
if yychar=0 then goto abort; (* end of input; abort *)
yychar := -1; goto next; (* clear lookahead char and try again *)
end;
shift:
(* go to new state, clear lookahead character: *)
yystate := yyn; yychar := -1; yyval := yylval;
if yyerrflag>0 then dec(yyerrflag);
goto parse;
reduce:
(* execute action, pop rule from stack, and go to next state: *)
if yydebug then writeln('reduce ', -yyn);
yyflag := yyfnone; yyaction(-yyn);
dec(yysp, yyr[-yyn].len);
if yygoto(yys[yysp], yyr[-yyn].sym, yyn) then yystate := yyn;
(* handle action calls to yyaccept, yyabort and yyerror: *)
case yyflag of
yyfaccept : goto accept;
yyfabort : goto abort;
yyferror : goto errlab;
end;
goto parse;
accept:
yyparse := 0; exit;
abort:
yyparse := 1; exit;
end(*yyparse*);
(* Lexical analyzer (implemented in Turbo Pascal for maximum efficiency): *)
function yylex : integer;
function end_of_input : boolean;
begin
end_of_input := (cno>length(line)) and eof(yyin)
end(*end_of_input*);
procedure scan;
(* scan for nonempty character, skip comments *)
procedure scan_comment;
var p : integer;
begin
p := pos('*/', copy(line, cno, length(line)));
if p>0 then
cno := cno+succ(p)
else
begin
while (p=0) and not eof(yyin) do
begin
readln(yyin, line);
inc(lno);
p := pos('*/', line)
end;
if p=0 then
begin
cno := succ(length(line));
error(open_comment_at_eof);
end
else
cno := succ(succ(p))
end
end(*scan_comment*);
begin
while not end_of_input do
if cno<=length(line) then
case line[cno] of
' ', tab : inc(cno);
'/' :
if (cno<length(line)) and (line[succ(cno)]='*') then
begin
inc(cno, 2);
scan_comment
end
else
exit
else
exit
end
else
begin
readln(yyin, line);
inc(lno); cno := 1;
end
end(*scan*);
function scan_ident : integer;
(* scan an identifier *)
var
idstr : String;
begin
idstr := line[cno];
inc(cno);
while (cno<=length(line)) and (
('A'<=upCase(line[cno])) and (upCase(line[cno])<='Z') or
('0'<=line[cno]) and (line[cno]<='9') or
(line[cno]='_') or
(line[cno]='.') ) do
begin
idstr := idstr+line[cno];
inc(cno)
end;
yylval := get_key(idstr);
scan;
if not end_of_input and (line[cno]=':') then
scan_ident := C_ID
else
scan_ident := ID
end(*scan_ident*);
function scan_literal: integer;
(* scan a literal, i.e. string *)
var
idstr : String;
oct_val : Byte;
begin
idstr := line[cno];
inc(cno);
while (cno<=length(line)) and (line[cno]<>idstr[1]) do
if line[cno]='\' then
if cno<length(line) then
begin
inc(cno);
case line[cno] of
'n' :
begin
idstr := idstr+nl;
inc(cno)
end;
'r' :
begin
idstr := idstr+cr;
inc(cno)
end;
't' :
begin
idstr := idstr+tab;
inc(cno)
end;
'b' :
begin
idstr := idstr+bs;
inc(cno)
end;
'f' :
begin
idstr := idstr+ff;
inc(cno)
end;
'0'..'7' :
begin
oct_val := ord(line[cno])-ord('0');
inc(cno);
while (cno<=length(line)) and
('0'<=line[cno]) and
(line[cno]<='7') do
begin
oct_val := oct_val*8+ord(line[cno])-ord('0');
inc(cno)
end;
idstr := idstr+chr(oct_val)
end
else
begin
idstr := idstr+line[cno];
inc(cno)
end
end
end
else
inc(cno)
else
begin
idstr := idstr+line[cno];
inc(cno)
end;
if cno>length(line) then
error(missing_string_terminator)
else
inc(cno);
if length(idstr)=2 then
begin
yylval := ord(idstr[2]);
scan_literal := LITERAL;
end
else if length(idstr)>1 then
begin
yylval := get_key(''''+copy(idstr, 2, pred(length(idstr)))+'''');
scan_literal := LITID;
end
else
scan_literal := ILLEGAL;
end(*scan_literal*);
function scan_num : integer;
(* scan an unsigned integer *)
var
numstr : String;
code : integer;
begin
numstr := line[cno];
inc(cno);
while (cno<=length(line)) and
('0'<=line[cno]) and (line[cno]<='9') do
begin
numstr := numstr+line[cno];
inc(cno)
end;
val(numstr, yylval, code);
if code=0 then
scan_num := NUMBER
else
scan_num := ILLEGAL;
end(*scan_num*);
function scan_keyword : integer;
(* scan %xy *)
function lookup(key : String; var tok : integer) : boolean;
(* table of Yacc keywords (unstropped): *)
const
no_of_entries = 11;
max_entry_length = 8;
keys : array [1..no_of_entries] of String[max_entry_length] = (
'0', '2', 'binary', 'left', 'nonassoc', 'prec', 'right',
'start', 'term', 'token', 'type');
toks : array [1..no_of_entries] of integer = (
PTOKEN, PNONASSOC, PNONASSOC, PLEFT, PNONASSOC, PPREC, PRIGHT,
PSTART, PTOKEN, PTOKEN, PTYPE);
var m, n, k : integer;
begin
(* binary search: *)
m := 1; n := no_of_entries;
lookup := true;
while m<=n do
begin
k := m+(n-m) div 2;
if key=keys[k] then
begin
tok := toks[k];
exit
end
else if key>keys[k] then
m := k+1
else
n := k-1
end;
lookup := false
end(*lookup*);
var
keywstr : String;
tok : integer;
begin
inc(cno);
if cno<=length(line) then
case line[cno] of
'<' :
begin
scan_keyword := PLEFT;
inc(cno)
end;
'>' :
begin
scan_keyword := PRIGHT;
inc(cno)
end;
'=' :
begin
scan_keyword := PPREC;
inc(cno)
end;
'%', '\' :
begin
scan_keyword := PP;
inc(cno)
end;
'{' :
begin
scan_keyword := LCURL;
inc(cno)
end;
'}' :
begin
scan_keyword := RCURL;
inc(cno)
end;
'A'..'Z', 'a'..'z', '0'..'9' :
begin
keywstr := line[cno];
inc(cno);
while (cno<=length(line)) and (
('A'<=upCase(line[cno])) and (upCase(line[cno])<='Z') or
('0'<=line[cno]) and (line[cno]<='Z') ) do
begin
keywstr := keywstr+line[cno];
inc(cno)
end;
if lookup(keywstr, tok) then
scan_keyword := tok
else
scan_keyword := ILLEGAL
end;
else scan_keyword := ILLEGAL
end
else
scan_keyword := ILLEGAL;
end(*scan_keyword*);
function scan_char : integer;
(* scan any single character *)
begin
scan_char := ord(line[cno]);
inc(cno)
end(*scan_char*);
var lno0, cno0 : integer;
begin
tokleng := 0;
scan;
lno0 := lno; cno0 := cno;
if end_of_input then
yylex := 0
else
case line[cno] of
'A'..'Z', 'a'..'z', '_' : yylex := scan_ident;
'''', '"' : yylex := scan_literal;
'0'..'9' : yylex := scan_num;
'%', '\' : yylex := scan_keyword;
'=' :
if (cno<length(line)) and (line[succ(cno)]='{') then
begin
inc(cno);
yylex := scan_char
end
else
yylex := scan_char;
else yylex := scan_char;
end;
if lno=lno0 then
tokleng := cno-cno0
end(*yylex*);
(* Main program: *)
var i : Integer;
begin
{$ifdef linux}
codfilepath:='/usr/lib/fpc/lexyacc/';
{$else}
codfilepath:=path(paramstr(0));
{$endif}
(* sign-on: *)
writeln(sign_on);
(* parse command line: *)
if paramCount=0 then
begin
writeln(usage);
writeln(options);
halt(0);
end;
yfilename := '';
pasfilename := '';
for i := 1 to paramCount do
if copy(paramStr(i), 1, 1)='-' then
if upper(paramStr(i))='-V' then
verbose := true
else if upper(paramStr(i))='-D' then
debug := true
else
begin
writeln(invalid_option, paramStr(i));
halt(1);
end
else if yfilename='' then
yfilename := addExt(paramStr(i), 'y')
else if pasfilename='' then
pasfilename := addExt(paramStr(i), 'pas')
else
begin
writeln(illegal_no_args);
halt(1);
end;
if yfilename='' then
begin
writeln(illegal_no_args);
halt(1);
end;
if pasfilename='' then pasfilename := root(yfilename)+'.pas';
lstfilename := root(yfilename)+'.lst';
(* open files: *)
assign(yyin, yfilename);
assign(yyout, pasfilename);
assign(yylst, lstfilename);
reset(yyin); if ioresult<>0 then fatal(cannot_open_file+yfilename);
rewrite(yyout); if ioresult<>0 then fatal(cannot_open_file+pasfilename);
rewrite(yylst); if ioresult<>0 then fatal(cannot_open_file+lstfilename);
(* search code template in current directory, then on path where Yacc
was executed from: *)
codfilename := 'yyparse.cod';
assign(yycod, codfilename);
reset(yycod);
if ioresult<>0 then
begin
codfilename := codfilepath+'yyparse.cod';
assign(yycod, codfilename);
reset(yycod);
if ioresult<>0 then fatal(cannot_open_file+codfilename);
end;
(* parse source grammar: *)
write('parse ... ');
lno := 0; cno := 1; line := '';
next_section;
if debug then writeln(yyout, '{$define yydebug}');
if yyparse=0 then
{ done }
else if yychar=0 then
error(unexpected_eof)
else
error(syntax_error);
if errors=0 then writeln('DONE');
(* close files: *)
close(yyin); close(yyout); close(yylst); close(yycod);
(* print statistics: *)
if errors>0 then
writeln( lno, ' lines, ',
errors, ' errors found.' )
else
begin
writeln( lno, ' lines, ',
n_rules-1, '/', max_rules-1, ' rules, ',
n_states, '/', max_states, ' s, ',
n_items, '/', max_items, ' i, ',
n_trans, '/', max_trans, ' t, ',
n_redns, '/', max_redns, ' r.');
if shift_reduce>0 then
writeln(shift_reduce, ' shift/reduce conflicts.');
if reduce_reduce>0 then
writeln(reduce_reduce, ' reduce/reduce conflicts.');
if never_reduced>0 then
writeln(never_reduced, ' rules never reduced.');
end;
if warnings>0 then writeln(warnings, ' warnings.');
{$ifndef fpc}
{$IFNDEF Win32}
writeln( n_bytes, '/', max_bytes, ' bytes of memory used.');
{$ENDIF}
{$endif}
(* terminate: *)
if errors>0 then
begin
erase(yyout);
if ioresult<>0 then ;
end;
if file_size(lstfilename)=0 then
erase(yylst)
else
writeln('(see ', lstfilename, ' for more information)');
halt(errors);
end(*Yacc*).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -