pyacc.y 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. /* YACC.Y: Yacc grammar for Yacc main program. 2-17-91, 4-30-91 AG
  2. To bootstrap Yacc, use Yacc iself to compile this grammar, then
  3. run tpc on the generated program.
  4. Note:
  5. This is not entirely the `official' syntax introduced by Johnson, but it
  6. should be compatible with UNIX Yacc (except for the differences specified
  7. in the program header, below), as described in the UNIX manual, including
  8. the language elements entitled as "old features supported but not
  9. encouraged."
  10. Bugs:
  11. - Processes $$'s, $i's, %} and } inside of comments in Turbo Pascal code
  12. (instead of ignoring them).
  13. Shift/reduce conflicts:
  14. This grammar will produce a number of shift/reduce conflicts caused by
  15. the error productions, since it does not specify unambigiously whether
  16. errors are to be handled in global structures (definitions and rules)
  17. or by enclosed syntactic constructs (e.g. symbols). Yacc will resolve
  18. these conflicts in favour of shift, which is o.k. (it means that
  19. errors will be caught in the innermost constructs with error handling,
  20. thus reducing the amount of skipped symbols in resynchronization).
  21. Error handling is done using the general method of Schreiner/Friedman
  22. (see Schreiner/Friedman, "Introduction to compiler construction with
  23. UNIX," 1985).
  24. */
  25. %{
  26. (*
  27. TP Yacc - Yet Another Compiler Compiler for Turbo Pascal
  28. Copyright (C) 1990-92 Albert Graef <[email protected]>
  29. Copyright (C) 1996 Berend de Boer <[email protected]>
  30. This program is free software; you can redistribute it and/or modify
  31. it under the terms of the GNU General Public License as published by
  32. the Free Software Foundation; either version 2 of the License, or
  33. (at your option) any later version.
  34. This program is distributed in the hope that it will be useful,
  35. but WITHOUT ANY WARRANTY; without even the implied warranty of
  36. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  37. GNU General Public License for more details.
  38. You should have received a copy of the GNU General Public License
  39. along with this program; if not, write to the Free Software
  40. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  41. $Revision$
  42. $Modtime: 96-08-01 11:24 $
  43. Last changes:
  44. Version 3.0 as of April 91
  45. Version 3.0a as of May 92 (bug fixes in precedence and type information
  46. updates)
  47. $History: YACC.PAS $
  48. *
  49. * ***************** Version 2 *****************
  50. * User: Berend Date: 96-10-10 Time: 21:16
  51. * Updated in $/Lex and Yacc/tply
  52. * Updated for protected mode, windows and Delphi 1.X and 2.X.
  53. ------------------------- Synopsis ------------------------
  54. Synopsis yacc [options] yacc-file[.y] [output-file[.pas]]
  55. Options
  56. -v "Verbose:" Yacc generates a readable description of the generated
  57. parser, written to yacc-file with new extension .lst.
  58. -d "Debug:" Yacc generates parser with debugging output.
  59. Description
  60. This is a reimplementation of the popular UNIX compiler generator
  61. Yacc for MS-DOS and Turbo Pascal.
  62. Differences from UNIX Yacc:
  63. - Produces output code for Turbo Pascal, rather than for C.
  64. - Does not support %union definitions. Instead, a value type is declared
  65. by specifying the type identifier *itself* as the tag of a %token
  66. or %type definition. Yacc will automatically generate an appropriate
  67. yylval variable of a variant record type (YYSType) which is capable of
  68. holding values of any of the types used in %token and %type.
  69. Type checking is *very* strict. If you use type definitions, then
  70. any symbol referred to in an action *must* have a type introduced
  71. in a type definition. Either the symbol must have been assigned a
  72. type in the definitions section, or the $<type-identifier> notation
  73. must be used. The syntax of the %type definition has been changed
  74. slightly to allow definitions of the form
  75. %type <type-identifier>
  76. (omitting the nonterminals) which may be used to declare types which
  77. are not assigned to any grammar symbol, but are used with the
  78. $<...> construct.
  79. - The parse tables constructed by this Yacc version are slightly greater
  80. than those constructed by UNIX Yacc, since a reduce action will only be
  81. chosen as the default action if it is the *only* action in the state.
  82. In difference, UNIX Yacc chooses a reduce action as the default action
  83. whenever it is the only *reduce* action of the state (even if there are
  84. other shift actions).
  85. This solves a bug in UNIX Yacc that makes the generated parser start
  86. error recovery too late with certain types of error productions (see
  87. also Schreiner/Friedman, "Introduction to compiler construction with
  88. UNIX," 1985). Also, errors will be caught sooner in most cases where
  89. standard Yacc would carry out an additional (default) reduction before
  90. detecting the error.
  91. ------------------------- Synopsis ------------------------
  92. *)
  93. {$IFDEF MsDos}
  94. {$M 16384,0,655360}
  95. {$ENDIF}
  96. {$IFDEF DPMI}
  97. {$M 32768}
  98. {$ENDIF}
  99. {$IFDEF Windows}
  100. {$M 32768,0}
  101. {$ENDIF}
  102. {$X+}
  103. {$I-}
  104. program Yacc;
  105. uses
  106. {$IFDEF Debug}
  107. {$IFDEF DPMI}
  108. YaccChk,
  109. {$ENDIF}
  110. {$ENDIF}
  111. {$IFDEF Windows}
  112. {$IFNDEF Console}
  113. WinCrt,
  114. {$ENDIF}
  115. {$ENDIF}
  116. YaccLib, YaccBase, YaccMsgs, YaccSem, YaccTabl, YaccPars;
  117. %}
  118. /* Lexical part of the Yacc language: */
  119. %token
  120. ID /* identifiers: {letter}{letter_or_digit}* */
  121. C_ID /* identifier which forms left side of rule, i.e. is
  122. followed by a colon */
  123. LITERAL /* single character literal */
  124. LITID /* multiple character literal */
  125. NUMBER /* nonnegative integers: {digit}+ */
  126. PTOKEN PLEFT PRIGHT PNONASSOC PTYPE PSTART PPREC
  127. /* reserved words: PTOKEN=%token, etc. */
  128. PP /* source sections separator %% */
  129. LCURL /* curly braces: %{ and %} */
  130. RCURL
  131. ',' ':' ';' '|' '{' '}' '<' '>' '='
  132. /* literals */
  133. ILLEGAL /* illegal input character */
  134. %start grammar
  135. %%
  136. /* Lexical entities, those that may give rise to syntax errors are augmented
  137. with error productions, and important symbols call yyerrok. */
  138. id : ID
  139. c_id : C_ID
  140. literal : LITERAL
  141. litid : LITID
  142. number : NUMBER
  143. ptoken : PTOKEN { yyerrok; }
  144. pleft : PLEFT { yyerrok; }
  145. pright : PRIGHT { yyerrok; }
  146. pnonassoc : PNONASSOC { yyerrok; }
  147. ptype : PTYPE { yyerrok; }
  148. pstart : PSTART { yyerrok; }
  149. pprec : PPREC
  150. pp : PP { yyerrok; }
  151. lcurl : LCURL
  152. rcurl : RCURL
  153. | error { error(rcurl_expected); }
  154. comma : ','
  155. colon : ':' { yyerrok; }
  156. semicolon : ';' { yyerrok; }
  157. bar : '|' { yyerrok; }
  158. lbrace : '{'
  159. rbrace : '}'
  160. | error { error(rbrace_expected); }
  161. langle : '<'
  162. rangle : '>'
  163. | error { error(rangle_expected); }
  164. eq : '='
  165. /* Syntax and semantic routines: */
  166. grammar : defs pp
  167. { sort_types;
  168. definitions;
  169. next_section; }
  170. rules
  171. { next_section;
  172. generate_parser;
  173. next_section; }
  174. aux_procs
  175. ;
  176. aux_procs : /* empty: aux_procs is optional */
  177. | pp { copy_rest_of_file; }
  178. ;
  179. defs : /* empty */
  180. | defs def { yyerrok; }
  181. | defs error { error(error_in_def); }
  182. ;
  183. def : pstart id
  184. { startnt := ntsym($2); }
  185. | pstart error
  186. { error(ident_expected); }
  187. | lcurl { copy_code; } rcurl
  188. | ptoken
  189. { act_prec := 0; }
  190. tag token_list
  191. | pleft
  192. { act_prec := new_prec_level(left); }
  193. tag token_list
  194. | pright
  195. { act_prec := new_prec_level(right); }
  196. tag token_list
  197. | pnonassoc
  198. { act_prec := new_prec_level(nonassoc); }
  199. tag token_list
  200. | ptype tag nonterm_list
  201. | ptype tag
  202. ;
  203. tag : /* empty: type tag is optional */
  204. { act_type := 0; }
  205. | langle id rangle
  206. { act_type := $2; add_type($2); }
  207. ;
  208. token_list : token_num
  209. | token_list token_num
  210. { yyerrok; }
  211. | token_list comma token_num
  212. { yyerrok; }
  213. | error
  214. { error(ident_expected); }
  215. | token_list error
  216. { error(error_in_def); }
  217. | token_list comma error
  218. { error(ident_expected); }
  219. ;
  220. token_num : literal
  221. { if act_type<>0 then
  222. sym_type^[$1] := act_type;
  223. if act_prec<>0 then
  224. sym_prec^[$1] := act_prec; }
  225. | litid
  226. { litsym($1, 0);
  227. if act_type<>0 then
  228. sym_type^[litsym($1, 0)] := act_type;
  229. if act_prec<>0 then
  230. sym_prec^[litsym($1, 0)] := act_prec; }
  231. | id
  232. { litsym($1, 0);
  233. if act_type<>0 then
  234. sym_type^[litsym($1, 0)] := act_type;
  235. if act_prec<>0 then
  236. sym_prec^[litsym($1, 0)] := act_prec; }
  237. | litid number
  238. { litsym($1, 0);
  239. if act_type<>0 then
  240. sym_type^[litsym($1, $2)] := act_type;
  241. if act_prec<>0 then
  242. sym_prec^[litsym($1, 0)] := act_prec; }
  243. | id number
  244. { litsym($1, 0);
  245. if act_type<>0 then
  246. sym_type^[litsym($1, $2)] := act_type;
  247. if act_prec<>0 then
  248. sym_prec^[litsym($1, 0)] := act_prec; }
  249. ;
  250. nonterm_list : nonterm
  251. | nonterm_list nonterm
  252. { yyerrok; }
  253. | nonterm_list comma nonterm
  254. { yyerrok; }
  255. | error
  256. { error(ident_expected); }
  257. | nonterm_list error
  258. { error(error_in_def); }
  259. | nonterm_list comma error
  260. { error(ident_expected); }
  261. ;
  262. nonterm : id
  263. { if act_type<>0 then
  264. sym_type^[ntsym($1)] := act_type; }
  265. ;
  266. rules : { next_section; }
  267. rule1
  268. | lcurl { copy_code; } rcurl
  269. { next_section; }
  270. rule1
  271. /* rules section may be prefixed
  272. with `local' Turbo Pascal
  273. declarations */
  274. | rules rule
  275. { yyerrok; }
  276. | error
  277. { error(error_in_rule); }
  278. | rules error
  279. { error(error_in_rule); }
  280. ;
  281. rule1 : c_id
  282. { start_rule(ntsym($1)); }
  283. colon
  284. { start_body; }
  285. body prec
  286. { end_body; }
  287. ;
  288. rule : rule1
  289. | bar
  290. { start_body; }
  291. body prec
  292. { end_body; }
  293. ;
  294. body : /* empty */
  295. | body literal
  296. { add_symbol($2); yyerrok; }
  297. | body litid
  298. { add_symbol(sym($2)); yyerrok; }
  299. | body id
  300. { add_symbol(sym($2)); yyerrok; }
  301. | body action
  302. { add_action; yyerrok; }
  303. | body error
  304. { error(error_in_rule); }
  305. ;
  306. action : lbrace { copy_action; } rbrace
  307. | eq { copy_single_action; }
  308. /* old language feature; code must be
  309. single statement ending with `;' */
  310. ;
  311. prec : /* empty */
  312. | pprec literal
  313. { add_rule_prec($2); }
  314. opt_action
  315. | pprec litid
  316. { add_rule_prec(litsym($2, 0)); }
  317. opt_action
  318. | pprec id
  319. { add_rule_prec(litsym($2, 0)); }
  320. opt_action
  321. | prec semicolon
  322. ;
  323. opt_action : /* empty */
  324. | action
  325. { add_action; }
  326. ;
  327. %%
  328. (* Lexical analyzer (implemented in Turbo Pascal for maximum efficiency): *)
  329. function yylex : integer;
  330. function end_of_input : boolean;
  331. begin
  332. end_of_input := (cno>length(line)) and eof(yyin)
  333. end(*end_of_input*);
  334. procedure scan;
  335. (* scan for nonempty character, skip comments *)
  336. procedure scan_comment;
  337. var p : integer;
  338. begin
  339. p := pos('*/', copy(line, cno, length(line)));
  340. if p>0 then
  341. cno := cno+succ(p)
  342. else
  343. begin
  344. while (p=0) and not eof(yyin) do
  345. begin
  346. readln(yyin, line);
  347. inc(lno);
  348. p := pos('*/', line)
  349. end;
  350. if p=0 then
  351. begin
  352. cno := succ(length(line));
  353. error(open_comment_at_eof);
  354. end
  355. else
  356. cno := succ(succ(p))
  357. end
  358. end(*scan_comment*);
  359. begin
  360. while not end_of_input do
  361. if cno<=length(line) then
  362. case line[cno] of
  363. ' ', tab : inc(cno);
  364. '/' :
  365. if (cno<length(line)) and (line[succ(cno)]='*') then
  366. begin
  367. inc(cno, 2);
  368. scan_comment
  369. end
  370. else
  371. exit
  372. else
  373. exit
  374. end
  375. else
  376. begin
  377. readln(yyin, line);
  378. inc(lno); cno := 1;
  379. end
  380. end(*scan*);
  381. function scan_ident : integer;
  382. (* scan an identifier *)
  383. var
  384. idstr : String;
  385. begin
  386. idstr := line[cno];
  387. inc(cno);
  388. while (cno<=length(line)) and (
  389. ('A'<=upCase(line[cno])) and (upCase(line[cno])<='Z') or
  390. ('0'<=line[cno]) and (line[cno]<='9') or
  391. (line[cno]='_') or
  392. (line[cno]='.') ) do
  393. begin
  394. idstr := idstr+line[cno];
  395. inc(cno)
  396. end;
  397. yylval := get_key(idstr);
  398. scan;
  399. if not end_of_input and (line[cno]=':') then
  400. scan_ident := C_ID
  401. else
  402. scan_ident := ID
  403. end(*scan_ident*);
  404. function scan_literal: integer;
  405. (* scan a literal, i.e. string *)
  406. var
  407. idstr : String;
  408. oct_val : Byte;
  409. begin
  410. idstr := line[cno];
  411. inc(cno);
  412. while (cno<=length(line)) and (line[cno]<>idstr[1]) do
  413. if line[cno]='\' then
  414. if cno<length(line) then
  415. begin
  416. inc(cno);
  417. case line[cno] of
  418. 'n' :
  419. begin
  420. idstr := idstr+nl;
  421. inc(cno)
  422. end;
  423. 'r' :
  424. begin
  425. idstr := idstr+cr;
  426. inc(cno)
  427. end;
  428. 't' :
  429. begin
  430. idstr := idstr+tab;
  431. inc(cno)
  432. end;
  433. 'b' :
  434. begin
  435. idstr := idstr+bs;
  436. inc(cno)
  437. end;
  438. 'f' :
  439. begin
  440. idstr := idstr+ff;
  441. inc(cno)
  442. end;
  443. '0'..'7' :
  444. begin
  445. oct_val := ord(line[cno])-ord('0');
  446. inc(cno);
  447. while (cno<=length(line)) and
  448. ('0'<=line[cno]) and
  449. (line[cno]<='7') do
  450. begin
  451. oct_val := oct_val*8+ord(line[cno])-ord('0');
  452. inc(cno)
  453. end;
  454. idstr := idstr+chr(oct_val)
  455. end
  456. else
  457. begin
  458. idstr := idstr+line[cno];
  459. inc(cno)
  460. end
  461. end
  462. end
  463. else
  464. inc(cno)
  465. else
  466. begin
  467. idstr := idstr+line[cno];
  468. inc(cno)
  469. end;
  470. if cno>length(line) then
  471. error(missing_string_terminator)
  472. else
  473. inc(cno);
  474. if length(idstr)=2 then
  475. begin
  476. yylval := ord(idstr[2]);
  477. scan_literal := LITERAL;
  478. end
  479. else if length(idstr)>1 then
  480. begin
  481. yylval := get_key(''''+copy(idstr, 2, pred(length(idstr)))+'''');
  482. scan_literal := LITID;
  483. end
  484. else
  485. scan_literal := ILLEGAL;
  486. end(*scan_literal*);
  487. function scan_num : integer;
  488. (* scan an unsigned integer *)
  489. var
  490. numstr : String;
  491. code : integer;
  492. begin
  493. numstr := line[cno];
  494. inc(cno);
  495. while (cno<=length(line)) and
  496. ('0'<=line[cno]) and (line[cno]<='9') do
  497. begin
  498. numstr := numstr+line[cno];
  499. inc(cno)
  500. end;
  501. val(numstr, yylval, code);
  502. if code=0 then
  503. scan_num := NUMBER
  504. else
  505. scan_num := ILLEGAL;
  506. end(*scan_num*);
  507. function scan_keyword : integer;
  508. (* scan %xy *)
  509. function lookup(key : String; var tok : integer) : boolean;
  510. (* table of Yacc keywords (unstropped): *)
  511. const
  512. no_of_entries = 11;
  513. max_entry_length = 8;
  514. keys : array [1..no_of_entries] of String[max_entry_length] = (
  515. '0', '2', 'binary', 'left', 'nonassoc', 'prec', 'right',
  516. 'start', 'term', 'token', 'type');
  517. toks : array [1..no_of_entries] of integer = (
  518. PTOKEN, PNONASSOC, PNONASSOC, PLEFT, PNONASSOC, PPREC, PRIGHT,
  519. PSTART, PTOKEN, PTOKEN, PTYPE);
  520. var m, n, k : integer;
  521. begin
  522. (* binary search: *)
  523. m := 1; n := no_of_entries;
  524. lookup := true;
  525. while m<=n do
  526. begin
  527. k := m+(n-m) div 2;
  528. if key=keys[k] then
  529. begin
  530. tok := toks[k];
  531. exit
  532. end
  533. else if key>keys[k] then
  534. m := k+1
  535. else
  536. n := k-1
  537. end;
  538. lookup := false
  539. end(*lookup*);
  540. var
  541. keywstr : String;
  542. tok : integer;
  543. begin
  544. inc(cno);
  545. if cno<=length(line) then
  546. case line[cno] of
  547. '<' :
  548. begin
  549. scan_keyword := PLEFT;
  550. inc(cno)
  551. end;
  552. '>' :
  553. begin
  554. scan_keyword := PRIGHT;
  555. inc(cno)
  556. end;
  557. '=' :
  558. begin
  559. scan_keyword := PPREC;
  560. inc(cno)
  561. end;
  562. '%', '\' :
  563. begin
  564. scan_keyword := PP;
  565. inc(cno)
  566. end;
  567. '{' :
  568. begin
  569. scan_keyword := LCURL;
  570. inc(cno)
  571. end;
  572. '}' :
  573. begin
  574. scan_keyword := RCURL;
  575. inc(cno)
  576. end;
  577. 'A'..'Z', 'a'..'z', '0'..'9' :
  578. begin
  579. keywstr := line[cno];
  580. inc(cno);
  581. while (cno<=length(line)) and (
  582. ('A'<=upCase(line[cno])) and (upCase(line[cno])<='Z') or
  583. ('0'<=line[cno]) and (line[cno]<='Z') ) do
  584. begin
  585. keywstr := keywstr+line[cno];
  586. inc(cno)
  587. end;
  588. if lookup(keywstr, tok) then
  589. scan_keyword := tok
  590. else
  591. scan_keyword := ILLEGAL
  592. end;
  593. else scan_keyword := ILLEGAL
  594. end
  595. else
  596. scan_keyword := ILLEGAL;
  597. end(*scan_keyword*);
  598. function scan_char : integer;
  599. (* scan any single character *)
  600. begin
  601. scan_char := ord(line[cno]);
  602. inc(cno)
  603. end(*scan_char*);
  604. var lno0, cno0 : integer;
  605. begin
  606. tokleng := 0;
  607. scan;
  608. lno0 := lno; cno0 := cno;
  609. if end_of_input then
  610. yylex := 0
  611. else
  612. case line[cno] of
  613. 'A'..'Z', 'a'..'z', '_' : yylex := scan_ident;
  614. '''', '"' : yylex := scan_literal;
  615. '0'..'9' : yylex := scan_num;
  616. '%', '\' : yylex := scan_keyword;
  617. '=' :
  618. if (cno<length(line)) and (line[succ(cno)]='{') then
  619. begin
  620. inc(cno);
  621. yylex := scan_char
  622. end
  623. else
  624. yylex := scan_char;
  625. else yylex := scan_char;
  626. end;
  627. if lno=lno0 then
  628. tokleng := cno-cno0
  629. end(*yylex*);
  630. (* Main program: *)
  631. var i : Integer;
  632. begin
  633. {$ifdef Unix}
  634. {$ifdef BSD}
  635. codfilepath:='/usr/local/lib/fpc/lexyacc/';
  636. {$else}
  637. codfilepath:='/usr/lib/fpc/lexyacc/';
  638. {$endif}
  639. {$else}
  640. codfilepath:=path(paramstr(0));
  641. {$endif}
  642. (* sign-on: *)
  643. writeln(sign_on);
  644. (* parse command line: *)
  645. if paramCount=0 then
  646. begin
  647. writeln(usage);
  648. writeln(options);
  649. halt(0);
  650. end;
  651. yfilename := '';
  652. pasfilename := '';
  653. for i := 1 to paramCount do
  654. if copy(paramStr(i), 1, 1)='-' then
  655. if upper(paramStr(i))='-V' then
  656. verbose := true
  657. else if upper(paramStr(i))='-D' then
  658. debug := true
  659. else
  660. begin
  661. writeln(invalid_option, paramStr(i));
  662. halt(1);
  663. end
  664. else if yfilename='' then
  665. yfilename := addExt(paramStr(i), 'y')
  666. else if pasfilename='' then
  667. pasfilename := addExt(paramStr(i), 'pas')
  668. else
  669. begin
  670. writeln(illegal_no_args);
  671. halt(1);
  672. end;
  673. if yfilename='' then
  674. begin
  675. writeln(illegal_no_args);
  676. halt(1);
  677. end;
  678. if pasfilename='' then pasfilename := root(yfilename)+'.pas';
  679. lstfilename := root(yfilename)+'.lst';
  680. (* open files: *)
  681. assign(yyin, yfilename);
  682. assign(yyout, pasfilename);
  683. assign(yylst, lstfilename);
  684. reset(yyin); if ioresult<>0 then fatal(cannot_open_file+yfilename);
  685. rewrite(yyout); if ioresult<>0 then fatal(cannot_open_file+pasfilename);
  686. rewrite(yylst); if ioresult<>0 then fatal(cannot_open_file+lstfilename);
  687. (* search code template in current directory, then on path where Yacc
  688. was executed from: *)
  689. codfilename := 'yyparse.cod';
  690. assign(yycod, codfilename);
  691. reset(yycod);
  692. if ioresult<>0 then
  693. begin
  694. codfilename := codfilepath+'yyparse.cod';
  695. assign(yycod, codfilename);
  696. reset(yycod);
  697. if ioresult<>0 then fatal(cannot_open_file+codfilename);
  698. end;
  699. (* parse source grammar: *)
  700. write('parse ... ');
  701. lno := 0; cno := 1; line := '';
  702. next_section;
  703. if debug then writeln(yyout, '{$define yydebug}');
  704. if yyparse=0 then
  705. { done }
  706. else if yychar=0 then
  707. error(unexpected_eof)
  708. else
  709. error(syntax_error);
  710. if errors=0 then writeln('DONE');
  711. (* close files: *)
  712. close(yyin); close(yyout); close(yylst); close(yycod);
  713. (* print statistics: *)
  714. if errors>0 then
  715. writeln( lno, ' lines, ',
  716. errors, ' errors found.' )
  717. else
  718. begin
  719. writeln( lno, ' lines, ',
  720. n_rules-1, '/', max_rules-1, ' rules, ',
  721. n_states, '/', max_states, ' s, ',
  722. n_items, '/', max_items, ' i, ',
  723. n_trans, '/', max_trans, ' t, ',
  724. n_redns, '/', max_redns, ' r.');
  725. if shift_reduce>0 then
  726. writeln(shift_reduce, ' shift/reduce conflicts.');
  727. if reduce_reduce>0 then
  728. writeln(reduce_reduce, ' reduce/reduce conflicts.');
  729. if never_reduced>0 then
  730. writeln(never_reduced, ' rules never reduced.');
  731. end;
  732. if warnings>0 then writeln(warnings, ' warnings.');
  733. {$ifndef fpc}
  734. {$IFNDEF Win32}
  735. writeln( n_bytes, '/', max_bytes, ' bytes of memory used.');
  736. {$ENDIF}
  737. {$endif}
  738. (* terminate: *)
  739. if errors>0 then
  740. begin
  741. erase(yyout);
  742. if ioresult<>0 then ;
  743. end;
  744. if file_size(lstfilename)=0 then
  745. erase(yylst)
  746. else
  747. writeln('(see ', lstfilename, ' for more information)');
  748. halt(errors);
  749. end(*Yacc*).