%{ /* This file is part of web2w. Copyright 2017 Martin Ruckert web2w 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 3 of the License, or (at your option) any later version. web2w 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 web2w. If not, see . Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen */ #include #include "web2w.h" /* the tag=token number of the left hand side symbol of a rule */ #define LHSS (yyr1[yyn]+FIRST_PASCAL_TOKEN-3) static int function=0; %} %code requires { #define PPSTYPE token * #define YYSTYPE PPSTYPE extern int ppparse(void); extern int ppdebug; } %token-table %defines %error_verbose %debug %define api.prefix "pp" %expect 1 %token PEOF 0 "end of file" %token WEBEOF "end of web" %token HEAD %token BAR %token PLEFT %token MLEFT %token RIGHT %token OPEN %token CLOSE %token TEXT %token NL %token HASH %token NMACRO %token OMACRO %token PMACRO %token PARAM %token EQ %token EQEQ %token ATSTAR %token ATSPACE %token ATD %token ATF %token ATLESS %token ATGREATER %token ELIPSIS %token ATP %token OCTAL %token HEX %token ATAT %token ATDOLLAR %token ATLEFT %token ATRIGHT %token ATINDEX %token ATINDEXTT %token ATINDEX9 %token ATT %token ATEQ %token ATAND %token ATBACKSLASH %token ATEX %token ATQM %token ATCOMMA %token ATSLASH %token ATBAR %token ATHASH %token ATPLUS %token ATSEMICOLON %token STRING %token CHAR %token INDENT %token METACOMMENT %token CSEMICOLON %token ID %token WDEBUG %token WSTAT %token WINIT %token WTINI %token WTATS %token WGUBED %token PRETURN "return" %token FIRST_PASCAL_TOKEN %token PPLUS "+" %token PMINUS "-" %token PSTAR "*" %token PSLASH "/" %token PEQ "=" %token PNOTEQ "<>" %token PLESS "<" %token PGREATER ">" %token PLESSEQ "<=" %token PGREATEREQ ">=" %token POPEN "(" %token PCLOSE ")" %token PSQOPEN "[" %token PSQCLOSE "]" %token PASSIGN ":=" %token PDOT "." %token PCOMMA "," %token PSEMICOLON ";" %token PMOD "mod" %token PDIV "div" %token PNIL "nil" %token POR "or" %token PAND "and" %token PNOT "not" %token PIF "if" %token PTHEN "then" %token PELSE "else" %token PREPEAT "repeat" %token PUNTIL "until" %token PWHILE "while" %token PDO "do" %token PFOR "for" %token PTO "to" %token PDOWNTO "downto" %token PBEGIN "begin" %token PEND "end" %token PGOTO "goto" %token PINTEGER "0-9" %token PREAL "real" %token POTHERS "others" %token PSTRING "'...'" %token PCHAR "'.'" %token PTYPECHAR "char type" %token PTYPEBOOL "bool type" %token PTYPEINT "integer type" %token PTYPEREAL "real type" %token PTYPEINDEX "index type" %token PID "identifier" %token PDEFVARID "variable definition" %token PDEFPARAMID "parameter definition" %token PDEFREFID "reference parameter definition" %token PCONSTID "constant" %token PDEFCONSTID "constant definition" %token PDEFTYPEID "typename definition" %token PDEFTYPESUBID "subrange typename definition" %token PARRAYFILETYPEID "array of file type" %token PARRAYFILEID "array of file name" %token PFUNCID "functionname" %token PDEFFUNCID "functionname definition" %token PPROCID "procedurename" %token PCALLID "call" %token PRETURNID "return value" %token PEXIT "final_end" %token PFBEGIN "function begin" %token PFEND "function end" %token PDOTDOT ".." %token PCOLON ":" %token PUP "^" %token PIN "in" %token PCASE "case" %token POF "of" %token PWITH "with" %token PCONST "const" %token PVAR "var" %token PTYPE "type" %token PARRAY "array" %token PRECORD "record" %token PSET "set" %token PFILE "file" %token PFUNCTION "function" %token PPROCEDURE "procedure" %token PLABEL "label" %token PPACKED "packed" %token PPROGRAM "program" %token PFORWARD "forward" %token CIGNORE %token CLABEL %token CLABELN %token CINTDEF %token CSTRDEF %token CMAIN %token CMAINEND %token CUNION %token CTSUBRANGE %token CINT %token CREFID "reference variable" %token CRETURN "C function return" %token CPROCRETURN "C procedure return" %token CCASE "C case" %token CCOLON "C :" %token CBREAK "break" %token CEMPTY "empty statement" %% program: programheading globals PBEGIN statements PEND PDOT { CHGTAG($3,CMAIN); CHGTAG($5,CMAINEND); IGN($6); wsemicolon($4,$5); } ; programheading: PPROGRAM PID PSEMICOLON {IGN($2); IGN($3); } ; globals: labels constants types variables procedures ; labels: | PLABEL labellist PSEMICOLON { IGN($3); } ; labellist: labeldecl | labellist PCOMMA labeldecl { IGN($2); } ; labeldecl: NMACRO {IGN($1); SYM($1)->obsolete=1; } | PINTEGER {IGN($1); } | PEXIT {IGN($1); } | labeldecl PPLUS PINTEGER {IGN($2); IGN($3); } ; constants: | PCONST constdefinitions | PCONST constdefinitions conststringdefinition ; constdefinitions: constdefinition | constdefinitions constdefinition ; constdefinition: PID PEQ PINTEGER PSEMICOLON { LNK($1,$2); LNK($2,$4); SETVAL($1,getval($3)); CHGID($1,PCONSTID); CHGTAG($1,CINTDEF); } ; conststringdefinition: PID PEQ PSTRING PSEMICOLON { seq($1,$4); CHGID($1,PCONSTID); CHGTAG($1,CSTRDEF);CHGTAG($2,PASSIGN); } ; types: | PTYPE typedefinitions { IGN($1); } ; typedefinitions: typedefinition | typedefinitions typedefinition ; typedefinition: PID PEQ subrange PSEMICOLON { DBG(dbgparse,"New Subrange Type: %s\n", SYM($1)->name); LNK($1,$2); IGN($2);LNK($2,$4); CHGTYPE($1,$3); CHGTAG($1,PDEFTYPEID); CHGTAG($2,CTSUBRANGE); UP($2,$3); } | PID PEQ type PSEMICOLON { DBG(dbgparse,"New Type: %s\n", SYM($1)->name); LNK($1,$2); IGN($2); LNK($2,$4); CHGTYPE($1,$3); LNK($3,$4); CHGTAG($1,PDEFTYPEID); } ; subrange: iconst PDOTDOT iconst {$$=join(PDOTDOT,$1,$3,$3->value-$1->value+1); } | PTYPECHAR {$$=join(PDOTDOT,join(PTYPECHAR,$1,$1,0), join(PTYPECHAR,$1,$1,255),256); } ; iconst: signed_iconst {$$=$1; } | iconst PPLUS simple_iconst {$$=join(PPLUS,$1,$3,$1->value+$3->value); } | iconst PMINUS simple_iconst {$$=join(PMINUS,$1,$3,$1->value-$3->value); } ; signed_iconst: simple_iconst {$$=$1; } | PPLUS simple_iconst {$$=join(PPLUS,NULL,$2,$2->value); } | PMINUS simple_iconst {$$=join(PMINUS,NULL,$2,-($2->value)); } ; simple_iconst: PINTEGER {$$=join(PINTEGER,$1,NULL,getval($1)); } | NMACRO {$$=join(NMACRO,$1,NULL,getval($1)); } | PCONSTID {$$=join(PCONSTID,$1,NULL,getval($1)); } ; file_type: packed PFILE POF typename {$$=$2; } |packed PFILE POF subrange {$$=$2; } ; packed: PPACKED | ; typename: PTYPEINT {$$=NULL; } | PTYPEREAL {$$=NULL; } | PTYPEBOOL {$$=NULL; } | PID {$$=NULL; } ; record_type: packed PRECORD fields PEND { LNK($2,$4); LNK($3,$4); if ($3) CHGTAG($4,PSEMICOLON); else IGN($4); $$=NULL; } | packed PRECORD variant_part PEND { LNK($2,$4); LNK($3,$4); IGN($4); $$=NULL; } | packed PRECORD fields PSEMICOLON variant_part PEND { LNK($2,$6); LNK($3,$4); LNK($5,$6); IGN($6); $$=NULL; } ; fields: recordsection {$$=$1; } | fields PSEMICOLON recordsection { LNK($1,$2); $$=$3; } ; /* in a recordsection the first PID links to the PCOLON, the recordsection points to the PCOLON */ recordsection: {$$=NULL; } | recids PCOLON type {LNK($1,$2); IGN($2); $$=$2; } | recids PCOLON subrange {LNK($1,$2); CHGTAG($2,CTSUBRANGE); UP($2,$3); $$=$2; } ; /* recids point to the first PID which is changed to PDEFVARID */ recids: PID {$$=$1; CHGTAG($1,PDEFVARID); } | recids PCOMMA PID {$$=$1; } ; variant_part: PCASE PID POF variants {IGN($1);IGN($2); CHGTAG($3,CUNION); $$=$3; } ; variants: variant | variants variant ; variant: PINTEGER PCOLON POPEN recordsection PCLOSE PSEMICOLON { IGN($1); IGN($2); IGN($3); LNK($4,$5); IGN($5); } | PINTEGER PCOLON POPEN recordsection PSEMICOLON recordsection PCLOSE PSEMICOLON { IGN($1); IGN($2); CHGTAG($3,PRECORD); LNK($3,$8); LNK($4,$5); LNK($6,$7); CHGTAG($7,PSEMICOLON); } ; type: typename | file_type | record_type ; array_type: packed PARRAY PSQOPEN iconst PDOTDOT iconst PSQCLOSE POF type {LNK($2,$3); UP($2,join(PDOTDOT,$4,$6,$6->value-$4->value+1)); LNK($3,$5); LNK($5,$7); LNK($7,$8);$$=$8; } | packed PARRAY PSQOPEN iconst PDOTDOT iconst PSQCLOSE POF subrange {LNK($2,$3); UP($2,join(PDOTDOT,$4,$6,$6->value-$4->value+1)); LNK($3,$5); LNK($5,$7); LNK($7,$8); CHGTAG($8,CTSUBRANGE); UP($8,$9);$$=$8; } | packed PARRAY PSQOPEN PID PSQCLOSE POF type {LNK($2,$3); UP($2,$4);LNK($3,$4); LNK($4,$5); LNK($5,$6);$$=$6; } | packed PARRAY PSQOPEN PID PSQCLOSE POF subrange {LNK($2,$3); UP($2,$4); LNK($3,$4); LNK($4,$5); LNK($5,$6); CHGTAG($6,CTSUBRANGE); UP($6,$7);$$=$6; } | packed PARRAY PSQOPEN PTYPECHAR PSQCLOSE POF type {LNK($2,$3); UP($2,join(PDOTDOT, join(PTYPECHAR,$1,$1,0),join(PTYPECHAR,$1,$1,255),256)); $3->link=join(PTYPECHAR,$3,$5,256); $3->link->link=$5; /* the PTYPECHAR comes from a macroexpansion, so we can not link it directly */ LNK($5,$6); $$=$6; } ; variables: | PVAR vardeclarations { IGN($1); } ; vardeclarations: vardeclaration | vardeclarations vardeclaration ; vardeclaration: varids PCOLON type PSEMICOLON { LNK($1,$2); IGN($2); LNK($2,$4); } | varids PCOLON array_type PSEMICOLON { LNK($1,$2); IGN($2); LNK($3,$4); LNK($2,$4); } | varids PCOLON subrange PSEMICOLON { LNK($1,$2); CHGTAG($2,CTSUBRANGE); UP($2,$3); LNK($2,$4); } ; varids: entire_var {CHGTAG($1,PDEFVARID); $$=$1; } | varids PCOMMA entire_var {LNK($1,$3);$$=$3; } ; procedures: | procedures procedure | procedures function ; locals: PVAR localvardeclarations { CHGTAG($1,PBEGIN); } | PLABEL locallabellist PSEMICOLON localvariables { CHGTAG($1,PBEGIN); IGN($3); } ; locallabellist: locallabeldecl | locallabellist PCOMMA locallabeldecl {IGN($2); } ; locallabeldecl: NMACRO {IGN($1); SYM($1)->obsolete=1; localize($1); } | PINTEGER {IGN($1); } | labeldecl PPLUS PINTEGER {IGN($2); IGN($3); } ; localvariables: | PVAR localvardeclarations { IGN($1); } ; localvardeclarations: localvardeclaration | localvardeclarations localvardeclaration ; localvardeclaration: localvarids PCOLON type PSEMICOLON { LNK($1,$2); IGN($2); LNK($2,$4); } | localvarids PCOLON array_type PSEMICOLON { LNK($1,$2); IGN($2); LNK($3,$4); LNK($2,$4); } | localvarids PCOLON subrange PSEMICOLON { LNK($1,$2); CHGTAG($2,CTSUBRANGE); UP($2,$3); LNK($2,$4); } ; localvarids: localentire_var {CHGTAG($1,PDEFVARID); $$=$1; } | localvarids PCOMMA localentire_var {LNK($1,$3);$$=$3; } ; localentire_var: PID {$$=$1; localize($1); } | CREFID {$$=$1; CHGTAG($1,PID); CHGID($1,PID); localize($1); } ; procedure: pheading locals PBEGIN statements PEND PSEMICOLON {IGN($3); IGN($6); wend($4,$5); wsemicolon($4,$5); scope_close(); } | pheading PBEGIN statements PEND PSEMICOLON { IGN($5); wend($3,$4); wsemicolon($3,$4); scope_close(); } | pheading PFORWARD PSEMICOLON { scope_close(); } ; function: fheading PBEGIN {function=1; } statements PEND PSEMICOLON {function=0; wreturn($4, 1,NULL); IGN($6); wsemicolon($4,$5); scope_close(); } | fheading locals PBEGIN {function=1; } statements PEND PSEMICOLON { int f_no=$1->sym_no; function=0; if (f_no==x_over_n || f_no==xn_over_d) { DBG(dbgcweb,"Discovered function %s; in line %d\n", SYM($1)->name,$1->lineno); CHGTAG($3,PFBEGIN); $3->sym_no=f_no; CHGTAG($6,PFEND); $6->sym_no=f_no; } else { IGN($3); wreturn($5,1,NULL); } wsemicolon($5,$6); IGN($7); scope_close(); } ; pid: PID {scope_open(); $$=$1; START_PARAM; } |PPROCID {scope_open(); $$=$1; START_PARAM; } |PFUNCID {scope_open(); $$=$1; START_PARAM; } ; pheading: PPROCEDURE pid PSEMICOLON { LNK($1,$3); CHGID($2,PPROCID); CHGVALUE($2,1); IGN($3); } | PPROCEDURE pid POPEN formals PCLOSE PSEMICOLON { LNK($1,$3); CHGID($2,PPROCID); CHGVALUE($2,param_mask); LNK($4,$5); IGN($6); } ; fheading: PFUNCTION pid PCOLON typename PSEMICOLON {$$=$2; LNK($1,$3); CHGID($2,PFUNCID); CHGVALUE($2,1);IGN($3); LNK($3,$5); IGN($5); } | PFUNCTION pid POPEN formals PCLOSE PCOLON typename PSEMICOLON {$$=$2; LNK($1,$3); CHGID($2,PFUNCID); CHGVALUE($2,param_mask); LNK($4,$5); LNK($5,$6); IGN($6); LNK($6,$8); IGN($8); } ; formals: formalparameters {$$=$1; } | formals PSEMICOLON formalparameters { LNK($1,$2); CHGTAG($2,PCOMMA); $$=$3; } ; formalparameters: params PCOLON typename { LNK($1,$2); IGN($2); $$=$2; } ; params: param {$$=$1; } | params PCOMMA param {LNK($1,$3);$$=$3; } ; param: entire_var {NEXT_PARAM; CHGTAG($1,PDEFPARAMID); $$=$1; } | PVAR entire_var {REF_PARAM; NEXT_PARAM; IGN($1); CHGTAG($2,PDEFREFID);CHGID($2,CREFID); $$=$2; } ; proc_stmt: PPROCID POPEN args PCLOSE {CHGTAG($1,PCALLID); $$=$1; UP($2,$1); pstring_args($1,$3); } | PCALLID POPEN args PCLOSE {$$=$1; UP($2,$1); pstring_args($1,$3); } | PPROCID {CHGTAG($1,PCALLID); $$=$1; } | PCALLID { $$=$1; } ; function_call: PFUNCID POPEN args PCLOSE {CHGTAG($1,PCALLID); $$=$4; UP($2,$1); } | PCALLID POPEN args PCLOSE { $$=$4; UP($2,$1); } | PFUNCID {CHGTAG($1,PCALLID);$$=$1; } | PCALLID {$$=$1; } ; args: arg {$$=$1; } | args PCOMMA arg {if ($3==NULL) $$=$1; else if ($1==NULL) $$=$3; else $$=join(PCOMMA,$1,$3,0); } ; arg: expression {$$=$1; } | write_arg {$$=$1; } | STRING {$$=$1; } | CHAR {$$=$1; } ; write_arg: expression PCOLON expression {$$=$2; } ; statements: statement {$$=$1; } | statements PSEMICOLON statement {$$=join(PSEMICOLON,$1,$3,0); } ; statement: stmt {$$=$1; } | label PCOLON stmt { clabel($1,0);$$=join(PCOLON,$1,$3,0); } | PEXIT PCOLON stmt { IGN($1); IGN($2); $$=join(PCOLON,$1,$3,0); } ; goto_stmt: PGOTO label { clabel($2,1); $$=join(PGOTO,$2,NULL,0); } | PGOTO PEXIT { IGN($1); $$=$2; } | CIGNORE PEXIT { $$=$2; } | PRETURN { if (function) clabel($1,1); else { CHGTAG($1,CPROCRETURN);$1->sym_ptr->value++; } $$=$1; } ; label: PINTEGER | NMACRO | CLABEL | NMACRO PPLUS PINTEGER {seq($1,$3); $$=$1; } ; stmt: simple_stmt | structured_stmt ; simple_stmt: empty_stmt | assign_stmt | return_stmt | goto_stmt | proc_stmt ; empty_stmt: {$$=join(CEMPTY,NULL,NULL,0); } ; assign_stmt: variable PASSIGN expression {$$=$2; } | variable PASSIGN STRING {$$=$2; pstring_assign($1,$3); } | variable PASSIGN POPEN STRING PCLOSE {$$=$2; pstring_assign($1,$4); } ; return_stmt: PFUNCID PASSIGN expression { $$=$1; } | CRETURN CIGNORE expression {$$=$1; } | CRETURN CIGNORE expression CIGNORE CIGNORE {$$=join(CRETURN,NULL,NULL,0); } | CRETURN {$$=$1; } | CPROCRETURN {$$=$1; } ; structured_stmt: compound_stmt | conditional_stmt | repetitive_stmt ; compound_stmt: PBEGIN statements PEND {$$=join(PBEGIN,$2,NULL,0); wsemicolon($2,$3); } ; conditional_stmt: if_stmt | case_stmt; if_stmt: PIF expression PTHEN statement {$$=join(PIF,$4,NULL,0); } | PIF expression PTHEN statement PELSE statement {wsemicolon($4,$5); $$=join(PELSE,$4,$6,0); } ; case_stmt: PCASE expression POF case_list PEND {LNK($1,$3); wsemicolon($4,$5);$$=join(PCASE,$4,NULL,0); } | PCASE expression POF case_list PSEMICOLON PEND {LNK($1,$3);$$=join(PCASE,$4,NULL,0); } ; case_list: case_element | case_list PSEMICOLON case_element {$$=join(CCASE,$1,$3,0); wsemicolon($1,$2); CHGTAG($2,CBREAK); UP($2,$1); } | case_list CBREAK case_element {$$=join(CCASE,$1,$3,0); /* etex parses same module twice */ } ; case_element: case_labels PCOLON statement { $$=$3; } | POTHERS statement {$$=$2; } ; case_labels: case_label | case_labels PCOMMA case_label {CHGTAG($2,CCOLON); CHGTEXT($2,": "); } | case_labels CCOLON case_label ; case_label: PINTEGER { winsert_after($1->previous,CCASE,"case "); } | NMACRO { winsert_after($1->previous,CCASE,"case "); } | PINTEGER PPLUS NMACRO {winsert_after($1->previous,CCASE,"case "); } | NMACRO PPLUS NMACRO {winsert_after($1->previous,CCASE,"case "); } | NMACRO PPLUS PINTEGER {winsert_after($1->previous,CCASE,"case "); } | CCASE NMACRO | CCASE PINTEGER | CCASE NMACRO PPLUS NMACRO | NMACRO PMINUS NMACRO PPLUS NMACRO {winsert_after($1->previous,CCASE,"case "); /* etex */ } ; repetitive_stmt: while_stmt | repeat_stmt | for_stmt ; while_stmt: PWHILE expression PDO statement {LNK($1,$3); $$=join(PWHILE,$4,NULL,0); } ; repeat_stmt: PREPEAT statements PUNTIL expression { wsemicolon($2,$3); $$=join(PREPEAT,$2,NULL,0); } ; for_stmt: PFOR PID PASSIGN expression PTO varlimit PDO statement { mark_for_variable($2,$1->lineno,0,VAR_LOOP); DBG(dbgfor,"for variable %s, limit variable in line %d\n", SYM($2)->name,$2->lineno); $$=join(PFOR,$8,NULL,0);LNK($1,$5);LNK($5,$7); } | PFOR PID PASSIGN expression PTO iconst PDO statement { mark_for_variable($2,$1->lineno,$6->value,TO_LOOP); DBG(dbgfor,"for variable %s, limit up in line %d\n", SYM($2)->name,$2->lineno); $$=join(PFOR,$8,NULL,0);LNK($1,$5);LNK($5,$7); } | PFOR PID PASSIGN expression PDOWNTO iconst PDO statement { mark_for_variable($2,$1->lineno,$6->value,DOWNTO_LOOP); DBG(dbgfor,"for variable %s, limit down in line %d\n", SYM($2)->name,$2->lineno); $$=join(PFOR,$8,NULL,0);LNK($1,$5);LNK($5,$7); } ; varlimit: variable | variable PMINUS expression | variable PPLUS expression| iconst PSTAR expression; variable: PID | CREFID | indexed_var | field_var | file_var; entire_var: PID {$$=$1; } | CREFID {$$=$1; CHGTAG($1,PID); CHGID($1,PID); } ; indexed_var: variable PSQOPEN expression PSQCLOSE | variable PSQOPEN STRING PSQCLOSE | PARRAYFILEID PSQOPEN expression PSQCLOSE ; field_var: variable PDOT PID ; file_var: variable PUP ; expression: simple_expr {$$=$1; } | simple_expr relop simple_expr {$$=$3; } | simple_expr PEQ STRING {$$=$3; } ; relop: PEQ | PNOTEQ | PLESS | PLESSEQ | PGREATER | PGREATEREQ; simple_expr: term {$$=$1; } | sign term {$$=$2; } | simple_expr addop term {$$=$3; } | simple_expr addop sign term {$$=$4; } ; sign: PPLUS | PMINUS ; addop: PPLUS | PMINUS | POR ; term: factor {$$=$1; } | term mulop factor {$$=$3; } ; mulop: PSTAR | PSLASH { DBG(dbgslash,"Pascal / in line %d\n",$1->lineno); } | PDIV | PMOD | PAND ; factor: variable | unsigned_const | POPEN expression PCLOSE {$$=$3; } | function_call | PNOT factor {$$=$2; } ; unsigned_const: real | PINTEGER | NMACRO | PSTRING | PCHAR | PCONSTID ; real: PREAL | PINTEGER PDOT PINTEGER {$$=$3; /* used in line 2361 */}; %% const char *tagname(int tag) { return yytname[YYTRANSLATE(tag)]; }