/* Statement processing statement * // * parameter description: fsys: the collection of symbols that can be used to restore syntax analysis if an error occurs */void Statement (const symset & fsys, const Int & lev, int & Tx)/* Expression Processing Process expression * // * parameter description: fsys: indicates the collection of symbols used to restore syntax analysis if an error occurs */{int I, cx1, CX2; /* statement */If (sym = ident)/* the so-called "statement" may be a value assignment statement, starting with an identifier */{I = position (ID, TX ); /* locate the identifier in the symbol table */if (I = 0)/* if not found */error (11 ); /* Throw error 11 */elseif (Table [I]. kind! = Variable)/* If this identifier is found in the symbol table, but this identifier is not the variable name */{error (12);/* Throw error 12 */I = 0; /* I sets 0 as the error flag */} getsym ();/* gets the next token. Normally, it should be assigned a value */If (sym = becomes) /* if it is indeed the value */getsym ();/* Get the next token, normally it should be an expression */elseerror (13 ); /* if no value is assigned after the left mark of the value assignment statement, a 13-digit error is thrown */expression (fsys, lev, Tx);/* processing expression */if (I! = 0)/* if no error occurs, I will not be 0. I refers to the position of the Left identifier of the current language name in the symbol table */Gen (STO, lev-table [I]. level, table [I]. ADR);/* generate a line to write the expression value to the STO target code in the specified memory */} elseif (sym = readsym)/* if it is not a value assignment statement, the read statement */{getsym ();/* is used to obtain the next token. Normally, it should be left parenthesis */If (sym! = Lparen)/* If the read Statement is followed by a non-left brace */error (34);/* Throw error No. 34 */elsedo {/* to obtain the parameter table in the brackets of the read Statement cyclically, generate the corresponding "read from the keyboard" target code */getsym ();/* Get a token. Normally, it should be a variable name */If (sym = ident) /* if it is indeed an identifier * // * There is a slight problem here, you should also determine whether this identifier is a variable name, if it is a constant name or process name, an error should occur */I = position (ID, TX);/* query the symbol table and locate it to I, when I cannot be found, I will be 0 */elseI = 0;/* if it is not an identifier, there is a problem. I set 0 as the error mark */if (I = 0) /* if an error exists */error (35);/* Throw error 35 */else/* otherwise, the corresponding target code is generated */{Gen (OPR, 0, 16);/* generate the 16th Operation Command: read numbers from the keyboard */Gen (STO, lev-table [I]. level, table [I]. ADR);/* generate the STO command and store the read value to the space where the specified variable is located */} getsym ();/* obtain the next token, if it is a comma, the read statement is not complete yet; otherwise, it should be the right parenthesis */} while (sym = comma);/* continuously generate code until the variable in the parameter table of the read Statement is traversed, this is not a comma. It should be a right brace */If (sym! = Rparen)/* if it is not the right parenthesis we expected */{error (33);/* Throw error 33 */while (! (IN (sym, fsys)/* depending on the fsys set, locate the next valid token and restore the syntax analysis */getsym ();} elsegetsym (); /* If the read statement ends normally, get the next token, which is generally a semicolon or end */} elseif (sym = writesym) /* If the Write statement */{getsym ();/* gets the next token, it should be a left bracket */If (sym = lparen) /* if it is a left brace */{do {/*, obtain each value in the brackets in sequence, and output */getsym ();/* to get a token, here it should be an identifier */expression (symset {rparen, comma} + fsys, lev, Tx);/* call the expression process analysis expression, add the right parenthesis and comma */Gen (OPR, 0, 14) to the set for error recovery./* generate Command 14: Output */} while (sym = comma) to the screen;/* loop until it is no longer a comma, then it should be a right brace */If (sym! = Rparen)/* if it is not a right brace */error (33);/* Throw error 33 */elsegetsym ();/* normally, you need to get the next token, prepare */} gen (OPR, 0, 15);/* to generate the target code for the operation on the 15th, function is to output a line break */*. Therefore, we can see that the Write statement in PL/0 is similar to the writeln statement in Pascal, and it is a line break with the output */} elseif (sym = callsym) /* if it is a call statement */{getsym ();/* Get the token, it should be a process name identifier */If (sym! = Ident)/* If the call is not followed by the identifier */error (14);/* Throw error No. 14 */else {I = position (ID, TX ); /* Find the corresponding Identifier from the symbol table */if (I = 0)/* if not found */error (11 ); /* error 11 */else/* If the identifier is found at the position I of the symbol table */If (Table [I]. kind = procedure)/* If this identifier is a process name */Gen (CAL, lev-table [I]. level, table [I]. ADR);/* generate the Cal target code, call this process */elseerror (15);/* If the call is not followed by the process name, the 15th error is thrown */getsym (); /* Get the next token and prepare for the following. */} elseif (sym = ifsym)/* if it is an if statement */{Ge Tsym ();/* obtain a token. It should be a logical expression */condition (symset {thensym, dosym} + fsys, lev, Tx ); /* analyze and compute the logical expression, and add the then and do statements in the error recovery set */If (sym = thensym)/* after the expression */getsym (); /* the token obtained after then should be a statement */elseerror (16);/* If then does not exist after if, a 16th error is thrown */cx1 = Cx; /* write down the pointer position of the current Code allocation */Gen (JPC, 0, 0);/* generate the conditional jump command. Set the jump position to 0, after the analysis, enter */Statement (fsys, lev, Tx);/* the statement after then analysis */code [cx1]. A = Cx;/* The jump position of the previous command line (indicated by cx1) should be the position pointed by the current CX */} e Lseif (sym = beginsym)/* If begin */{getsym ();/* Get the next token */Statement (symset {semicolon, endsym} + fsys, lev, TX);/* analyze and process the begin and end statements */while (in (sym, symset {semicolon} + statbegsys )) /* if you encounter a semicolon or a statement prefix after analyzing the next sentence */{If (sym = semicolon) /* If the statement is a semicolon (may be a null statement) */getsym ();/* Get the next token for further analysis */elseerror (10 ); /* if there is no semicolon between the statement and the statement, the system Returns Error 10 */Statement (symset {semicolon, endsym} + fsys, lev, Tx ); /* analyze a statement */} If (Sym = endsym)/* If the statement has been fully analyzed, end */getsym () should be encountered;/* is indeed End, read the next token */elseerror (17 ); /* if it is not end, a 17 error is thrown */} elseif (sym = whilesym)/* If a while statement */{cx1 = Cx; /* write down the current Code allocation position, which is the starting position of the while loop */getsym ();/* Get the next token, it should be a logical expression */condition (symset {dosym} + fsys, lev, Tx);/* analysis and calculation of this logical expression */CX2 = Cx; /* write down the current Code allocation position, which is the start position of the statement in the while do */Gen (JPC, 0, 0);/* generate the conditional jump command, enter 0 */If (sym = dosym)/* after the logical expression, it must be D. O statement */getsym ();/* Get the next token */elseerror (18);/* Do is missing after condition *, and error 18 */Statement (fsys, lev, TX);/* analyze the DO statement block */Gen (JMP, 0, cx1);/* jump to the cx1 position cyclically, that is, make another logical judgment */code [CX2]. A = Cx;/* change the jump position filled in 0 to the current position, and complete the processing of the while statement */} test (fsys, symset (), 19 ); /* if the current statement is processed successfully, symbols in the fsys set will be encountered. If not, the 19 th error will be thrown */}/* statement */; /* block in the syntax analysis process * // * parameter: lev: the level of the syntax analysis * // * TX: symbol table pointer * // * fsys: word set used for error recovery */void block (INT levet, int Tx, Const symset & fsys) {int DX;/* Data Allocation Index * // * Data Segment memory allocation pointer, pointing to the offset position of the next allocated space in the data segment */INT tx0; /* initial table Index * // * records the position of the symbol table at the beginning of the current layer */INT cx0; /* initial code Index * // * records the position of the code segment allocation at the beginning of this layer * // * block */dx = 3; /* The address indicator shows the relative position of the local volume allocated to each layer. The reason for setting the initial value to 3 is that each layer has three spaces at the beginning for storing static link SL, dynamic link DL, and return address Ra */tx0 = TX; /* The initial symbol table Pointer Points to the starting position of the symbol at the current layer in the symbol table */table [TX]. ADR = Cx;/* mark the start position of the current layer code in the current position of the symbol table */Gen (JMP, 0, 0);/* generate a line of jump command, unknown jump position: enter 0 */If (levmax)/* if the number of nested layers in the current process is greater than the maximum number of nested layers */error (32 ); /* issue error No. 32 */do {/* start to process all declarations in the source program cyclically */If (sym = constsym)/* if the current token is a reserved word of const, start to declare constants */{getsym ();/* Get the next token. Normally, it should be the identifier used as the constant name */do {/* repeatedly declare constants */constdeclar Ation (lev, Tx, dx);/* declares the constant with the current token */while (sym = comma) /* If a comma is encountered, the next constant */{getsym () is repeatedly declared;/* gets the next token, which is exactly the identifier */constdeclaration (lev, Tx, dx ); /* declare the constant with the current token */} If (sym = semicolon)/* If the constant declaration ends, a semicolon */getsym () should be encountered (); /* Get the next token and prepare for the next cycle */elseerror (5 ); /* If a semicolon is not encountered after the constant declaration statement ends, the system will issue error 5 */} while (sym = ident);/* If a non-identifier is encountered, then the constant declaration ends */}/* the syntax of the constant declaration here is different from the ebnf paradigm in the textbook: it can accept the declaration method as follows, and according to the E The BNF paradigm cannot draw the following syntax: const A = 3, B = 3; C = 6; D = 7, E = 8; that is, it can accept constant declarations separated by semicolons or commas, while only declarations separated by commas can be accepted according to the ebnf paradigm */If (sym = varsym) /* if the current token is a reserved var word, start variable declaration, similar to the constant Declaration */{getsym ();/* Get the next token, normally, it should be an identifier */do {/* used as the variable name to repeatedly declare the variable */vardeclaration (lev, Tx, dx ); /* declare a variable with the current token as the identifier */while (sym = comma)/* If a comma is encountered, repeatedly declare the next variable */{getsym (); /* Get the next token, which is exactly the identifier */vardeclaration (lev, Tx, dx);/* declares that the current token is Identifier variable */} If (sym = semicolon)/* If the variable declaration ends, a semicolon */getsym () should be encountered;/* Get the next token, prepare for the next round of loop */elseerror (5);/* If the variable declaration statement does not encounter a semicolon after it ends, issue error 5 */} while (sym = ident ); /* If a non-identifier is encountered, the variable declaration ends * // * There is also a problem with the above constant Declaration: there is a conflict with the PL/0 syntax specification. */} While (sym = procsym)/* cyclically declare sub-Processes */{getsym ();/* Get the next token, normally, it should be the process name identifier */If (sym = ident)/* If the token is indeed the identifier */{enter (procedure, lev, Tx, dx ); /* log in to the name table */getsym ();/* Get the next token. Normally, it should be a semicolon */} elseerror (4 ); /* Otherwise, error 4 */If (sym = semicolon)/* if the current token is a semicolon */getsym ();/* Get the next token, recursive call to prepare for syntax analysis */elseerror (5);/* Otherwise, error No. 5 */block (lev1, TX, symset {semicolon} + fsys) is thrown ); /* recursively call the syntax analysis process. Add one at the current level and pass the header index and valid word character */If (sym = semicolon) /* after recursive return, the current token should be the semicolon after the last end of the recursive call */{getsym ();/* Get the next token */test (statbegsys + symset {Ident, procsym}, fsys, 6);/* check whether the current token is valid. If the token is invalid, use fsys to restore the syntax analysis and throw Error 6 */} elseerror (5 ); /* If the post-declaration symbol is not a semicolon, the system will throw error 5 */} test (statbegsys + symset {ident}, declbegsys, 7);/* check whether the current status is valid, if the program does not conform to the rules, use the Declaration start symbol to make error recovery, and throw the 7 th Error */} while (in (sym, declbegsys);/* until the declarative source program has been analyzed, continue to run down and analyze the main program */code [Table [tx0]. ADR]. A = Cx;/* change the jump position of the previously generated jump statement to the current position * // * record in the symbol table */table [tx0]. ADR = Cx;/* The address is the address allocated to the current Code */table [tx0]. size = DX;/* The length is the current data segment allocation position */cx0 = Cx;/* write down the current Code allocation position */Gen (_ int, 0, dx ); /* generate the space allocation command and allocate DX space */Statement (symset {semicolon, endsym} + fsys, lev, Tx ); /* process the currently encountered statement or statement block */Gen (OPR, 0, 0);/* generate the operation instruction returned from the subroutine */test (fsys, symset (), 8);/* use fsys to check whether the current status is valid. If the current status is invalid, an error 8 */listcode (cx0) is thrown ); /* list the pcode code of the current layer */}/* block */;