📄 cgen.c
字号:
/* cgen.c
* The code generator implementation to the TINY compiler
* (generates code for TM machine)
*
* Compiler Construction: Principles and Practice
* Kenneth C. Louden
* 编译原理及实践
* (美) Kenneth C. Louden 著
* 冯博琴 冯岚 等译
* 机械工业出版社 IBSN 7-111-07703-2
* 源代码:zwf编辑并修订
* Code Modify:
*/
#include "globals.h"
#include "symtab.h"
#include "code.h"
#include "cgen.h"
/* tmpOffset is the memory offset for temps
* It is decremented each time a temp is
* store, and incremented when loaded again
*/
static int tmpOffset = 0;
/* prototype for internal recursive code generator */
static void cGen(TreeNode * tree);
/* Procedure genStmt generates code at a statment node */
static void genStmt(TreeNode * tree)
{
TreeNode *p1, *p2, *p3;
int sLoc1, sLoc2, cLoc;
int loc;
switch (tree->kind.stmt) {
case IfK:
if (TraceCode)
emitComment("-> if");
p1 = tree->child[0];
p2 = tree->child[1];
p3 = tree->child[2];
/* generate code for test expression */
cGen(p1);
sLoc1 = emitSkip(1);
emitComment("if: jump to else belongs here");
/* recurse on then part */
cGen(p2);
sLoc2 = emitSkip(1);
emitComment("if: jump to end belongs here");
cLoc = emitSkip(0);
emitBackup(sLoc1);
emitRM_Abs("JEQ", ac, cLoc, "if: jmp tp else");
emitRestore();
/* recurse on else part */
cGen(p3);
cLoc = emitSkip(0);
emitBackup(sLoc2);
emitRM_Abs("LDA", pc, cLoc, "jmp to end");
emitRestore();
if (TraceCode)
emitComment("<- if");
break;
case RepeatK:
if (TraceCode)
emitComment("-> repeat");
p1 = tree->child[0];
p2 = tree->child[1];
sLoc1 = emitSkip(0);
emitComment("repeat: jump after body comes back here");
/* generate code for body */
cGen(p1);
/* generate code for test */
cGen(p2);
emitRM_Abs("JEQ", ac, sLoc1, "repeat: jmp back to body");
if (TraceCode)
emitComment("<- repeat");
break;
case AssignK:
if (TraceCode)
emitComment("-> assign");
/* generate code for rhs */
cGen(tree->child[0]);
/* now store value */
loc = st_lookup(tree->attr.name);
emitRM("ST", ac, loc, gp, "assign: store value");
if (TraceCode)
emitComment("<- assign");
break;
case ReadK:
emitRO("IN", ac, 0, 0, "read integer value");
loc = st_lookup(tree->attr.name);
emitRM("ST", ac, loc, gp, "read: store value");
break;
case WriteK:
/* generate code for expression to write */
cGen(tree->child[0]);
/* now output it */
emitRO("OUT", ac, 0, 0, "write ac");
break;
default:
break;
}
}
/* Procedure genExp generate code at an expression node */
static void genExp(TreeNode * tree)
{
int loc;
TreeNode *p1, *p2;
switch (tree->kind.exp) {
case ConstK:
if (TraceCode)
emitComment("-> Const");
/* gen code to load integer constant using LDC */
emitRM("LDC", ac, tree->attr.val, 0, "load const");
if (TraceCode)
emitComment("<- Const");
break;
case IdK:
if (TraceCode)
emitComment("-> Id");
loc = st_lookup(tree->attr.name);
emitRM("LD", ac, loc, gp, "load id value");
if (TraceCode)
emitComment("<- Id");
break;
case OpK:
if (TraceCode)
emitComment("-> Op");
p1 = tree->child[0];
p2 = tree->child[1];
/* gen code for ac = left arg */
cGen(p1);
/* gen code tp push left operand */
emitRM("ST", ac, tmpOffset--, mp, "op: push left");
/* gen code for ac = right operand */
cGen(p2);
/* now load left operand */
emitRM("LD", ac1, ++tmpOffset, mp, "op: load left");
switch (tree->attr.op) {
case PLUS:
emitRO("ADD", ac, ac1, ac, "op +");
break;
case MINUS:
emitRO("SUB", ac, ac1, ac, "op -");
break;
case TIMES:
emitRO("MUL", ac, ac1, ac, "op *");
break;
case OVER:
emitRO("DIV", ac, ac1, ac, "op /");
break;
// case '%':
// emitRO("%",ac,ac1,ac,"op %");
// break;
case LT:
emitRO("SUB", ac, ac1, ac, "op <");
emitRM("JLT", ac, 2, pc, "br if true");
emitRM("LDC", ac, 0, ac, "false case");
emitRM("LDA", pc, 1, pc, "unconditional jmp");
emitRM("LDC", ac, 1, ac, "true case");
break;
case GT: /* Larry */
emitRO("SUB", ac, ac1, ac, "op >");
emitRM("JGT", ac, 2, pc, "br if true");
emitRM("LDC", ac, 0, ac, "false case");
emitRM("LDA", pc, 1, pc, "unconditional jmp");
emitRM("LDC", ac, 1, ac, "true case");
break;
case LE: /* Larry */
emitRO("SUB", ac, ac1, ac, "op <=");
emitRM("JLE", ac, 2, pc, "br if true");
emitRM("LDC", ac, 0, ac, "false case");
emitRM("LDA", pc, 1, pc, "unconditional jmp");
emitRM("LDC", ac, 1, ac, "true case");
break;
case GE: /* Larry */
emitRO("SUB", ac, ac1, ac, "op >=");
emitRM("JGE", ac, 2, pc, "br if true");
emitRM("LDC", ac, 0, ac, "false case");
emitRM("LDA", pc, 1, pc, "unconditional jmp");
emitRM("LDC", ac, 1, ac, "true case");
break;
case NE: /* Larry */
emitRO("SUB", ac, ac1, ac, "op <>");
emitRM("JNE", ac, 2, pc, "br if true");
emitRM("LDC", ac, 0, ac, "false case");
emitRM("LDA", pc, 1, pc, "unconditional jmp");
emitRM("LDC", ac, 1, ac, "true case");
break;
case EQ:
emitRO("SUB", ac, ac1, ac, "op ==");
emitRM("JEQ", ac, 2, pc, "br if true");
emitRM("LDC", ac, 0, ac, "false case");
emitRM("LDA", pc, 1, pc, "unconditional jmp");
emitRM("LDC", ac, 1, ac, "true case");
break;
default:
emitComment("BUG: Unknown operator");
break;
}
if (TraceCode)
emitComment("<- Op");
break;
default:
break;
}
}
/* Procedure cGen recursively generate code by
* tree traversal
*/
static void cGen(TreeNode * tree)
{
if (tree != NULL) {
switch (tree->nodekind) {
case StmtK:
genStmt(tree);
break;
case ExpK:
genExp(tree);
break;
default:
break;
}
cGen(tree->sibling);
}
}
/* the primary function of the code generator */
/* Procedure codeGen generate code to a code
* file by traversal of the syntax tree. the
* second paramater (codefile) is the file name
* of the code file, and is used tp print the
* file name as a comment in the code file
*/
void codeGen(TreeNode * syntaxTree, char *codefile)
{
char *s = malloc(strlen(codefile) + 7);
strcpy(s, "File: ");
strcat(s, codefile);
emitComment("TINY Compilation to TM Code");
emitComment(s);
/* generate standard prelude */
emitComment("Standard prelund:");
emitRM("LD", mp, 0, ac, "load maxaddress from location 0");
emitRM("ST", ac, 0, ac, "clear location 0");
emitComment("End of standard prelude.");
/* generate code for TINY program */
cGen(syntaxTree);
/* finish */
emitComment("End of execution.");
emitRO("HALT", 0, 0, 0, "");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -