Procedures: Code Generation
This content discusses the procedures and code generation process in COP 3402 System Software for the Fall 2014 semester. It explores the structure of machine code in a compiled procedure, illustrating the sequence of operations involved. Details are provided on jump operations, nested procedures, address allocation, and code replacement considerations in the context of program execution.
Download Presentation

Please find below an Image/Link to download the presentation.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author.If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.
You are allowed to download the files provided on this website for personal or commercial use, subject to the condition that they are used lawfully. All files are the property of their respective owners.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author.
E N D
Presentation Transcript
Procedures: Code Generation COP 3402 System Software Fall 2014
Procedures: PM/0 code look In general, when a procedure is compiled, the machine code will look like this: 00 jmp 0 6 01 jmp 0 2 02 inc 0 5 03 lit 0 2 04 sto 0 5 05 opr 0 0 06 inc 0 4 07 cal 0 2 08 opr 0 0 procedure A; var y; begin y:= 2; end; call A. This code corresponds to the main block.
Procedures: PM/0 code look 00 jmp 0 6 01 jmp 0 2 02 inc 0 5 03 lit 0 2 04 sto 0 5 05 opr 0 0 06 inc 0 4 07 cal 0 2 08 opr 0 0 First comes a jump to the actual procedure code. Then we reserve space for the AR and variables. Later comes the code for the procedure. Finally, we return from the call.
Procedures: PM/0 code look 00 jmp 0 6 01 jmp 0 2 02 inc 0 5 03 lit 0 2 04 sto 0 5 05 opr 0 0 06 inc 0 4 07 cal 0 2 08 opr 0 0 First comes a jump to the actual procedure code. Then we reserve space for the AR and variables. Later comes the code for the procedure. Finally, we return from the call. How do I know the address for the first jump?
Step 1: The jump operation jmpCodeAddr = 00 When we have nested procedures, we don t know where to jump at the time we have to generate the jump operation. 00 jmp 0 ?? We must remember where the jump is in order to replace the correct address later.
Step 1: The jump operation jmpCodeAddr = 00 When we have nested procedures, we don t know where to jump at the time we have to generate the jump operation. 00 jmp 0 ?? 01 jmp 0 2 02 inc 0 5 03 lit 0 2 04 sto 0 5 05 opr 0 0 We must remember where the jump is in order to replace the correct address later.
Step 1: The jump operation jmpCodeAddr = 00 When we have nested procedures, we don t know where to jump at the time we have to generate the jump operation. 00 jmp 0 ?? 01 jmp 0 2 02 inc 0 5 03 lit 0 2 04 sto 0 5 05 opr 0 0 06 inc 0 4 We must remember where the jump is in order to replace the correct address later.
Step 1: The jump operation jmpCodeAddr = 00 When we have nested procedures, we don t know where to jump at the time we have to generate the jump operation. 00 jmp 0 6 01 jmp 0 2 02 inc 0 5 03 lit 0 2 04 sto 0 5 05 opr 0 0 06 inc 0 4 We must remember where the jump is in order to replace the correct address later.
Step 1: The jump operation When we parse the procedure declaration, we inserted it s name into the Symbol Table, and the address is the next code address, which is the address of the initial JMP. Once we know the address where the procedure code starts, we must: Update the jump operation.
Step 2: Reserve space A procedure must reserve space for it s activation record and variables, before its actual code starts. We must keep track of how much space we should reserve. It should be 4 at least (for the AR), and must increase for each declared variable. Be careful: each procedure must keep track of their own space, don t use a global variable. To reserve space, we generate a inc operation. gen(INC, 0, SPACE);
Step 3: Procedure code generation Now we can generate code for the procedure. This will be handle by the statement function.
Step 4: The return call This one is simple: just generate a return operation (opr 0 0).
Code Generation for Procedure Step 1: Generate a jump operation. Store the address of this jump. Keep parsing/generating code. Update the jump address. Step 2: Reserve Space Step 3: Generate the procedure code (parse the statements). Step 4: Generate a return operation.
Who will handle all this? The code generation for a procedure is handle by the block function. <proc-decl> ::= procedure <ident> ; <block> ; | e <program> ::= <block> . <block> ::= <const-decl> <var-decl> <proc-decl> <statement>
<block> Parser Procedure <block> ::= <const-decl> <var-decl> <proc-decl> <statement> procedure BLOCK(); begin if TOKEN = const then CONST-DECL(); if TOKEN = var then VAR-DECL(); if TOKEN = procedure then PROC-DECL(); STATEMENT(); end;
<block> Parser and Code Generation procedure BLOCK(); begin space = 4; jmpaddr = gen(JMP, 0, 0); // Step 1 if TOKEN = const then CONST-DECL(); if TOKEN = var then space += VAR-DECL(); if TOKEN = procedure then PROC-DECL(); code[jmpaddr].addr = NEXT_CODE_ADDR; gen(INC, 0, space); // Step 2 STATEMENT(); // Step 3 gen(OPR, 0, 0); // Step 4 end;
Keep track of lexicographical level We need to set the correct lexicographical each time we generate a LOD, STO or CAL operation. One way is to keep track of the current lexicographical level in a global variable. The lexicographical level increases when we enter the BLOCK procedure, and decreases when we exit it.
<block> Parser and Code Generation procedure BLOCK(); begin level++; space = 4; jmpaddr = gen(JMP, 0, 666); if TOKEN = const then CONST-DECL(); if TOKEN = var then space += VAR-DECL(); if TOKEN = procedure then PROC-DECL(); code[jmpaddr].addr = NEXT_CODE_ADDR; gen(INC, 0, space); STATEMENT(); gen(RTN, 0, 0); level--; end;
Keep track of lexicographical level To generate a LOD or STO, the correct lexicographical level is given by: level var_level For example: procedure A; var y; procedure B; var x; begin x = y; end; begin y:= 2; end; call A. LOD level-y_level y_addr STO level-x_level x_addr y_level = 1 x_level = 2 LOD 2-1 5 STO 2-2 5 curr_level = 2 LOD 1 5 STO 0 5
call Code Generation At this point, we already know the procedure address, so the call code is easy to generate. procedure STATEMENT; begin else if TOKEN = "call" then begin GET_TOKEN(); if TOKEN <> IDENT then ERROR (missing identifier); GET_TOKEN(); end
call Code Generation At this point, we already know the procedure address, so the call code is easy to generate. procedure STATEMENT; begin else if TOKEN = "call" then begin GET_TOKEN(); if TOKEN <> IDENT then ERROR (missing identifier); i = find(TOKEN); if i == 0 then ERROR (Undeclared identifier); if symboltype(i) == PROCEDURE then gen(CAL, level-symbollevel(i), symboladdr(i)); else ERROR(call must be followed by a procedure identifier); GET_TOKEN(); end