1 / 21

Procedures: Code Generation

Procedures: Code Generation. COP 3402 Software Systems Summer 2014. Procedures: PM/0 code look. In general, when a procedure is compiled, the machine code looks like this:. 00 jmp 0 0 6 01 jmp 0 0 2 02 inc 0 0 5 03 lit 0 0 2 04 sto 0 0 5 05 opr 0 0 0 06 inc 0 0 4

joy
Download Presentation

Procedures: Code Generation

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Procedures: Code Generation COP 3402 Software Systems Summer 2014

  2. Procedures: PM/0 code look • In general, when a procedure is compiled, the machine code looks like this: 00 jmp0 0 6 01 jmp0 0 2 02 inc 0 0 5 03 lit 0 0 2 04 sto0 0 5 05 opr0 0 0 06 inc 0 0 4 07 cal 0 0 2 08 rtn 0 0 0 procedure A; var y; begin y:= 2; end; call A. This code corresponds to the “program” block.

  3. Procedures: PM/0 code look 00 jmp0 0 6 01 jmp0 0 2 02 inc 0 0 5 03 lit 0 0 2 04 sto0 0 5 05 opr0 0 0 06 inc 0 0 4 07 cal 0 0 2 08 rtn 0 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.

  4. Procedures: PM/0 code look • How do I know the address for the first jump? 00 jmp0 0 6 01 jmp0 0 2 02 inc 0 0 5 03 lit 0 0 2 04 sto0 0 5 05 opr0 0 0 06 inc 0 0 4 07 cal 0 0 2 08 rtn 0 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.

  5. 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. • We must remember where the jump is in order to replace the correct address later. 00 jmp0 0 ??

  6. 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. • We must remember where the jump is in order to replace the correct address later. 00 jmp0 0 ?? 01 jmp0 0 2 02 inc 0 0 5 03 lit 0 0 2 04 sto0 0 5 05 opr0 0 0

  7. 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. • We must remember where the jump is in order to replace the correct address later. 00 jmp0 0 6 01 jmp0 0 2 02 inc 0 0 5 03 lit 0 0 2 04 sto0 0 5 05 opr0 0 0 …

  8. 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. • We must remember where the jump is in order to replace the correct address later. 00 jmp0 0 6 01 jmp0 0 2 02 inc 0 0 5 03 lit 0 0 2 04 sto0 0 5 05 opr0 0 0 • 06 inc 0 0 4 …

  9. Step 1: The “jump” operation • When we parse the procedure declaration, we inserted it’s name into the Symbol Table, but we didn’t know it’s address. • procedure MyProc; • Once we know the address where the procedure code starts, we must: • Update the jump operation. • Update the procedure address in the symbol table.

  10. 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, 0, SPACE);

  11. Step 3: Procedure code generation • Now we can generate code for the procedure. • This will be handle by the “statement” function.

  12. Step 4: The return call • This one is simple: just generate a return operation (rtn 0 0 0).

  13. Code Generation for Procedure • Step 1: Generate a jump operation. • Store the address of this jump. • Keep parsing/generating code. • Update the jump address. • Update the procedure address in the Symbol Table. • Step 2: Reserve Space • Step 3: Generate the procedure code (parse the statements). • Step 4: Generate a return operation.

  14. 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>

  15. <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;

  16. <block> Parser and Code Generation procedure BLOCK(); begin space = 4; jmpaddr = gen(JMP, 0, 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].m = NEXT_CODE_ADDR; gen(INC, 0, 0, space); // Step 2 STATEMENT(); // Step 3 gen(RTN, 0, 0, 0); // Step 4 end;

  17. 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 …

  18. 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, 0, 0, symboladdr(i)); • else ERROR(call must be followed by a procedure identifier); GET_TOKEN(); end …

  19. Keep track of lexicographical level • We need to set the correct lexicographical each time we generate a LOD or STO 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.

  20. <block> Parser and Code Generation procedure BLOCK(); begin current_level++; space = 4; jmpaddr = gen(JMP, 0, 0, 0); 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, 0, space); STATEMENT(); gen(RTN, 0, 0, 0); current_level--; end;

  21. Keep track of lexicographical level • To generate a LOD or STO, the correct lexicographical level is given by: current_level – var_level • For example: LOD regcurr_level-y_levely_addr STO regcurr_level-x_levelx_addr LOD reg2-1 5 STO reg2-25 LOD reg1 5 STO reg0 5 procedure A; var y; procedure B; var x; begin x = y; end; begin y:= 2; end; call A. y_level = 1 x_level = 2 curr_level = 2

More Related