* pi - Pascal interpreter code translator
* Charles Haley, Bill Joy UCB
* Version 1.0 August 1977
* pxp - Pascal execution profiler
* Version 1.0 August 1977
* Yacc grammar for UNIX Pascal
* This grammar is processed by the commands in the shell script
* "gram" to yield parse tables and semantic routines in the file
* "y.tab.c" and a header defining the lexical tokens in "yy.h".
* In order for the syntactic error recovery possible with this
* grammar to work, the grammar must be processed by a yacc which
* has been modified to fully enumerate possibilities in states
* which involve the symbol "error".
* The parser used for Pascal also uses a different encoding of
* the test entries in the action table which speeds the parse.
* A version of yacc which will work for Pascal is included on
* the distribution table as "eyacc".
* The "gram" script also makes the following changes to the "y.tab.c"
* 1) Causes yyval to be declared int *.
* 2) Loads the variable yypv into a register as yyYpv so that
* the arguments $1, ... are available as yyYpv[1] etc.
* This produces much smaller code in the semantic actions.
* 3) Deletes the unused array yysterm.
* 4) Moves the declarations up to the flag line containing
* '##' to the file yy.h so that the routines which use
* these "magic numbers" don't have to all be compiled at
* 5) Creates the semantic restriction checking routine yyEactr
* by processing action lines containing `@'.
* This compiler uses a different version of the yacc parser, a
* different yyerror which is called yerror, and requires more
* lookahead sets than normally provided by yacc.
* Source for the yacc used with this grammar is included on
* Some of the terminal declarations are out of the most natural
* alphabetic order because the error recovery
* will guess the first of equal cost non-terminals.
* This makes, e.g. YTO preferable to YDOWNTO.
YFOR YFORWARD YFUNCTION YGOTO
YPROCEDURE YPROG YRECORD YREPEAT
YSET YSTRING YTHEN YDOWNTO
YASSERT YCASELAB YILLCH YLAST
* PRECEDENCE DECLARATIONS
* Highest precedence is the unary logical NOT.
* Next are the multiplying operators, signified by '*'.
* Lower still are the binary adding operators, signified by '+'.
* Finally, at lowest precedence and non-associative are the relationals.
%left '*' '/' YDIV YMOD YAND '&'
* The following line marks the end of the yacc
* Constant definitions which are removed from
* y.tab.c and placed in the file y.tab.h.
prog_hedr decls procs block '.'
= funcend($1, $4, lineof($5));
YPROG YID '(' id_list ')' ';'
= $$ = funcbody(funchdr(tree5(T_PROG, lineof($1), $2, fixlist($4), NIL)));
yyPerror("Malformed program statement", PPROG);
* Should make a program statement
* with "input" and "output" here.
$$ = funcbody(funchdr(tree5(T_PROG, lineof($1), NIL, NIL, NIL)));
$$ = tree3(T_BSTL, lineof($1), fixlist($2));
constend(), typeend(), varend(), trfree();
yyPerror("Malformed declaration", PDECL);
= label(fixlist($2), lineof($1));
= $$ = newlist($1 == NIL ? NIL : *hash($1, 1));
= $$ = addlist($1, $3 == NIL ? NIL : *hash($3, 1));
= constbeg($1, line2of($2)), const(lineof($3), $2, $4);
const_decl YID '=' const ';'
= const(lineof($3), $2, $4);
constbeg($1, line2of($1));
yyPerror("Malformed const declaration", PDECL);
= typebeg($1, line2of($2)), type(lineof($3), $2, $4);
type_decl YID '=' type ';'
= type(lineof($3), $2, $4);
typebeg($1, line2of($1));
yyPerror("Malformed type declaration", PDECL);
YVAR id_list ':' type ';'
= varbeg($1, line2of($3)), var(lineof($3), fixlist($2), $4);
var_decl id_list ':' type ';'
= var(lineof($3), fixlist($2), $4);
yyPerror("Malformed var declaration", PDECL);
* PROCEDURE AND FUNCTION DECLARATION PART
pheadres decls procs block ';'
= funcend($1, $4, lineof($5));
porf YID params ftype ';'
= $$ = funchdr(tree5($1, lineof($5), $2, $3, $4));
= $$ = tree3(T_PVAL, fixlist($1), $3);
= $$ = tree3(T_PVAR, fixlist($2), $4);
YFUNCTION id_list ':' type
= $$ = tree3(T_PFUNC, fixlist($2), $4);
= $$ = tree2(T_PPROC, fixlist($2));
= $$ = tree2(T_CSTRNG, $1);
= $$ = tree2(T_PLUSC, $2);
= $$ = tree2(T_MINUSC, $2);
= $$ = tree2(T_CINT, $1);
= $$ = tree2(T_CBINT, $1);
= $$ = tree2(T_CFINT, $1);
= $$ = tree3(T_TYPTR, lineof($1), tree2(T_ID, $2));
= $$ = tree3(T_TYPACK, lineof($1), $2);
= $$ = tree3(T_TYSCAL, lineof($1), fixlist($2));
= $$ = tree4(T_TYRANG, lineof($2), $1, $3);
YARRAY '[' simple_type_list ']' YOF type
= $$ = tree4(T_TYARY, lineof($1), fixlist($3), $6);
= $$ = tree3(T_TYFILE, lineof($1), $3);
= $$ = tree3(T_TYSET, lineof($1), $3);
$$ = setuptyrec( lineof( $1 ) , $2 );
simple_type_list ',' simple_type
= $$ = tree4(T_FLDLST, lineof(NIL), fixlist($1), $2);
= yyPerror("Malformed record declaration", PDECL);
= $$ = tree4(T_RFIELD, lineof($2), fixlist($1), $3);
YCASE type_id YOF variant_list
= $$ = tree5(T_TYVARPT, lineof($1), NIL, $2, fixlist($4));
YCASE YID ':' type_id YOF variant_list
= $$ = tree5(T_TYVARPT, lineof($1), $2, $4, fixlist($6));
= yyPerror("Malformed record declaration", PDECL);
const_list ':' '(' field_list ')'
= $$ = tree4(T_TYVARNT, lineof($2), fixlist($1), $4);
= $$ = tree4(T_TYVARNT, lineof($2), fixlist($1), NIL);
if ((p = $1) != NIL && (q = p[1])[0] == T_IFX) {
= if ((q = $1) != NIL && (p = q[1]) != NIL && p[0] == T_IF) {
if (yyshifts >= 2 && yychar == YELSE) {
yerror("Deleted ';' before keyword else");
yyPerror("Malformed statement in case", PSTAT);
= $$ = tree4(T_CSTAT, lineof($2), fixlist($1), $3);
= $$ = tree4(T_CSTAT, lineof($1), NIL, $2);
= $$ = tree4(T_LABEL, lineof($2), $1 == NIL ? NIL : *hash($1, 1), $3);
= $$ = tree4(T_PCALL, lineof(yyline), $1, NIL);
proc_id '(' wexpr_list ')'
= $$ = tree4(T_PCALL, lineof($2), $1, fixlist($3));
$$ = tree3(T_BLOCK, lineof($1), fixlist($2));
YCASE expr YOF cstat_list YEND
$$ = tree4(T_CASE, lineof($1), $2, fixlist($4));
= $$ = tree4(T_WITH, lineof($1), fixlist($2), $4);
= $$ = tree4(T_WHILE, lineof($1), $2, $4);
YREPEAT stat_list YUNTIL expr
= $$ = tree4(T_REPEAT, lineof($3), fixlist($2), $4);
YFOR assign YTO expr YDO stat
= $$ = tree5(T_FORU, lineof($1), $2, $4, $6);
YFOR assign YDOWNTO expr YDO stat
= $$ = tree5(T_FORD, lineof($1), $2, $4, $6);
= $$ = tree3(T_GOTO, lineof($1), *hash($2, 1));
= $$ = tree5(T_IF, lineof($1), $2, $4, NIL);
YIF expr YTHEN stat YELSE stat
= $$ = tree5(T_IFEL, lineof($1), $2, $4, $6);
YIF expr YTHEN stat YELSE
= $$ = tree5(T_IFEL, lineof($1), $2, $4, NIL);
= $$ = tree3(T_ASRT, lineof($1), $3);
yyPerror("Malformed statement", PSTAT);
= $$ = tree4(T_ASGN, lineof($2), $1, $4);
yyPerror("Missing/malformed expression", PEXPR);
expr relop expr %prec '<'
= $$ = tree4($2, $1[1] == SAWCON ? $3[1] : $1[1], $1, $3);
= $$ = tree3(T_PLUS, $2[1], $2);
= $$ = tree3(T_MINUS, $2[1], $2);
expr addop expr %prec '+'
= $$ = tree4($2, $1[1] == SAWCON ? $3[1] : $1[1], $1, $3);
expr divop expr %prec '*'
= $$ = tree4($2, $1[1] == SAWCON ? $3[1] : $1[1], $1, $3);
= $$ = tree2(T_NIL, NOCON);
= $$ = tree3(T_STRNG, SAWCON, $1);
= $$ = tree3(T_INT, NOCON, $1);
= $$ = tree3(T_BINT, NOCON, $1);
= $$ = tree3(T_FINT, NOCON, $1);
func_id '(' wexpr_list ')'
= $$ = tree4(T_FCALL, NOCON, $1, fixlist($3));
= $$ = tree3(T_NOT, NOCON, $2);
= $$ = tree3(T_CSET, SAWCON, fixlist($2));
= $$ = tree3(T_CSET, SAWCON, NIL);
= $$ = tree3(T_RANG, $1, $3);
@ return (identis(var, VAR));
= $1[3] = fixlist($1[3]);
array_id '[' expr_list ']'
= $$ = setupvar($1, tree2(T_ARY, fixlist($3)));
qual_var '[' expr_list ']'
= $1[3] = addlist($1[3], tree2(T_ARY, fixlist($3)));
= $$ = setupvar($1, setupfield($3, NIL));
= $1[3] = addlist($1[3], setupfield($3, NIL));
= $$ = setupvar($1, tree1(T_PTR));
= $1[3] = addlist($1[3], tree1(T_PTR));
* Expression with write widths
= $$ = tree4(T_WEXP, $1, $3, NIL);
= $$ = tree4(T_WEXP, $1, $3, $5);
= $$ = tree4(T_WEXP, $1, NIL, $2);
= $$ = tree4(T_WEXP, $1, $3, $4);
* Identifier productions with semantic restrictions
* For these productions, the character @ signifies
* that the associated C statement is to provide
* the semantic restriction for this reduction.
* These lines are made into a procedure yyEactr, similar to
* yyactr, which determines whether the corresponding reduction
* is permitted, or whether an error is to be signaled.
* A zero return from yyEactr is considered an error.
* YyEactr is called with an argument "var" giving the string
* name of the variable in question, essentially $1, although
* $1 will not work because yyEactr is called from loccor in
= @ return (identis(var, CONST));
@ return (identis(var, TYPE));
$$ = tree3(T_TYID, lineof(yyline), $1);
= @ return (identis(var, VAR));
= @ return (identis(var, ARRAY));
= @ return (identis(var, PTRFILE));
= @ return (identis(var, RECORD));
= @ return (identis(var, FIELD));
= @ return (identis(var, PROC));
= @ return (identis(var, FUNC));