📄 yacc.y
字号:
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 + -