315 lines
9.2 KiB
C
315 lines
9.2 KiB
C
/****************************************************/
|
|
/* File: util.c */
|
|
/* Utility function implementation */
|
|
/* for the TINY compiler */
|
|
/* Compiler Construction: Principles and Practice */
|
|
/* Kenneth C. Louden */
|
|
/****************************************************/
|
|
|
|
#include "util.h"
|
|
#include "globals.h"
|
|
|
|
/* Procedure printToken prints a token
|
|
* and its lexeme to the listing file
|
|
*/
|
|
void printToken(TokenType token, const char *tokenString) {
|
|
switch (token) {
|
|
case IF:
|
|
case ELSE:
|
|
case WHILE:
|
|
case RETURN:
|
|
case INT:
|
|
case VOID:
|
|
fprintf(listing,
|
|
"reserved word: %s\n", tokenString);
|
|
break;
|
|
case ASSIGN:
|
|
fprintf(listing, "=\n");
|
|
break;
|
|
case EQ:
|
|
fprintf(listing, "==\n");
|
|
break;
|
|
case NE:
|
|
fprintf(listing, "!=\n");
|
|
break;
|
|
case LT:
|
|
fprintf(listing, "<\n");
|
|
break;
|
|
case LE:
|
|
fprintf(listing, "<=\n");
|
|
break;
|
|
case GT:
|
|
fprintf(listing, ">\n");
|
|
break;
|
|
case GE:
|
|
fprintf(listing, ">=\n");
|
|
break;
|
|
case PLUS:
|
|
fprintf(listing, "+\n");
|
|
break;
|
|
case MINUS:
|
|
fprintf(listing, "-\n");
|
|
break;
|
|
case TIMES:
|
|
fprintf(listing, "*\n");
|
|
break;
|
|
case OVER:
|
|
fprintf(listing, "/\n");
|
|
break;
|
|
case LPAREN:
|
|
fprintf(listing, "(\n");
|
|
break;
|
|
case RPAREN:
|
|
fprintf(listing, ")\n");
|
|
break;
|
|
case LBRACE:
|
|
fprintf(listing, "[\n");
|
|
break;
|
|
case RBRACE:
|
|
fprintf(listing, "]\n");
|
|
break;
|
|
case LCURLY:
|
|
fprintf(listing, "{\n");
|
|
break;
|
|
case RCURLY:
|
|
fprintf(listing, "}\n");
|
|
break;
|
|
case SEMI:
|
|
fprintf(listing, ";\n");
|
|
break;
|
|
case COMMA:
|
|
fprintf(listing, ",\n");
|
|
break;
|
|
case ENDFILE:
|
|
fprintf(listing, "EOF\n");
|
|
break;
|
|
case NUM:
|
|
fprintf(listing,
|
|
"NUM, val= %s\n", tokenString);
|
|
break;
|
|
case ID:
|
|
fprintf(listing,
|
|
"ID, name= %s\n", tokenString);
|
|
break;
|
|
case ERROR:
|
|
fprintf(listing,
|
|
"ERROR: %s\n", tokenString);
|
|
break;
|
|
default: /* should never happen */
|
|
fprintf(listing, "Unknown token: %d\n", token);
|
|
}
|
|
}
|
|
|
|
/* Function newStmtNode creates a new statement
|
|
* node for syntax tree construction
|
|
*/
|
|
TreeNode *newStmtNode(StmtKind kind) {
|
|
TreeNode *t = (TreeNode *) malloc(sizeof(TreeNode));
|
|
int i;
|
|
if (t == NULL)
|
|
fprintf(listing, "Out of memory error at line %d\n", lineno);
|
|
else {
|
|
for (i = 0; i < MAXCHILDREN; i++) t->child[i] = NULL;
|
|
t->sibling = NULL;
|
|
t->nodekind = StmtK;
|
|
t->kind.stmt = kind;
|
|
t->lineno = lineno;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
/* Function newExpNode creates a new expression
|
|
* node for syntax tree construction
|
|
*/
|
|
TreeNode *newExpNode(ExpKind kind) {
|
|
TreeNode *t = (TreeNode *) malloc(sizeof(TreeNode));
|
|
int i;
|
|
if (t == NULL)
|
|
fprintf(listing, "Out of memory error at line %d\n", lineno);
|
|
else {
|
|
for (i = 0; i < MAXCHILDREN; i++) t->child[i] = NULL;
|
|
t->sibling = NULL;
|
|
t->nodekind = ExpK;
|
|
t->kind.exp = kind;
|
|
t->lineno = lineno;
|
|
t->type = Void;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
TreeNode *newDeclNode(DeclKind kind) {
|
|
TreeNode *t = (TreeNode *) malloc(sizeof(TreeNode));
|
|
int i;
|
|
if (t == NULL)
|
|
fprintf(listing, "Out of memory error at line %d\n", lineno);
|
|
else {
|
|
for (i = 0; i < MAXCHILDREN; i++) t->child[i] = NULL;
|
|
t->sibling = NULL;
|
|
t->nodekind = DeclK;
|
|
t->kind.decl = kind;
|
|
t->lineno = lineno;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
TreeNode *newTypeNode(TypeKind kind) {
|
|
TreeNode *t = (TreeNode *) malloc(sizeof(TreeNode));
|
|
int i;
|
|
if (t == NULL)
|
|
fprintf(listing, "Out of memory error at line %d\n", lineno);
|
|
else {
|
|
for (i = 0; i < MAXCHILDREN; i++) t->child[i] = NULL;
|
|
t->sibling = NULL;
|
|
t->nodekind = TypeK;
|
|
t->kind.type = kind;
|
|
t->lineno = lineno;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
/* Function copyString allocates and makes a new
|
|
* copy of an existing string
|
|
*/
|
|
char *copyString(char *s) {
|
|
int n;
|
|
char *t;
|
|
if (s == NULL) return NULL;
|
|
n = strlen(s) + 1;
|
|
t = malloc(n);
|
|
if (t == NULL)
|
|
fprintf(listing, "Out of memory error at line %d\n", lineno);
|
|
else
|
|
strcpy(t, s);
|
|
return t;
|
|
}
|
|
|
|
/* Variable indentno is used by printTree to
|
|
* store current number of spaces to indent
|
|
*/
|
|
static int indentno = 0;
|
|
|
|
/* macros to increase/decrease indentation */
|
|
#define INDENT indentno += 2
|
|
#define UNINDENT indentno -= 2
|
|
|
|
/* printSpaces indents by printing spaces */
|
|
static void printSpaces(void) {
|
|
int i;
|
|
for (i = 0; i < indentno; i++)
|
|
fprintf(listing, " ");
|
|
}
|
|
|
|
void printType(TreeNode *tree) {
|
|
switch (tree->type) {
|
|
case Void:
|
|
fprintf(listing, "void");
|
|
break;
|
|
case Integer:
|
|
fprintf(listing, "int");
|
|
break;
|
|
case IntegerArray:
|
|
fprintf(listing, "int[]");
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* procedure printTree prints a syntax tree to the
|
|
* listing file using indentation to indicate subtrees
|
|
*/
|
|
void printTree(TreeNode *tree) {
|
|
int i;
|
|
INDENT;
|
|
while (tree != NULL) {
|
|
printSpaces();
|
|
if (tree->nodekind == StmtK) {
|
|
switch (tree->kind.stmt) {
|
|
case CompK:
|
|
fprintf(listing, "Compound Statement:\n");
|
|
break;
|
|
case IfK:
|
|
fprintf(listing, "%s:\n",
|
|
(tree->child[2] != NULL) ? "If-Else Statement" : "If Statement");
|
|
break;
|
|
case IterK:
|
|
fprintf(listing, "While Statement:\n");
|
|
break;
|
|
case ReturnK:
|
|
fprintf(listing, "Return Statement:\n");
|
|
break;
|
|
default:
|
|
fprintf(listing, "Unknown StmtNode kind\n");
|
|
break;
|
|
}
|
|
} else if (tree->nodekind == ExpK) {
|
|
switch (tree->kind.exp) {
|
|
case AssignK:
|
|
fprintf(listing, "Assign:\n");
|
|
break;
|
|
case OpK:
|
|
fprintf(listing, "Op: ");
|
|
printToken(tree->attr.op, "\0");
|
|
break;
|
|
case ConstK:
|
|
fprintf(listing, "Const: %d\n", tree->attr.val);
|
|
break;
|
|
case IdK:
|
|
fprintf(listing, "Variable: name = %s\n", tree->attr.name);
|
|
break;
|
|
case ArrIdK:
|
|
fprintf(listing, "Variable: name = %s\n", tree->attr.name);
|
|
break;
|
|
case CallK:
|
|
fprintf(listing, "Call: function name = %s\n", tree->attr.name);
|
|
break;
|
|
default:
|
|
fprintf(listing, "Unknown ExpNode kind\n");
|
|
break;
|
|
}
|
|
} else if (tree->nodekind == DeclK) {
|
|
switch (tree->kind.decl) {
|
|
case FuncK:
|
|
fprintf(listing, "Function Declaration: name = %s, return type = ", tree->attr.name);
|
|
printType(tree);
|
|
fprintf(listing, "\n");
|
|
break;
|
|
case VarK:
|
|
fprintf(listing, "Variable Declaration: name = %s, type = ", tree->attr.name);
|
|
printType(tree);
|
|
fprintf(listing, "\n");
|
|
break;
|
|
case ArrVarK:
|
|
fprintf(listing, "Variable Declaration: name = %s, type = ", tree->attr.name);
|
|
printType(tree);
|
|
fprintf(listing, "\n");
|
|
break;
|
|
case NonArrParamK:
|
|
if (tree->type == Void)
|
|
fprintf(listing, "Void Parameter\n");
|
|
else {
|
|
fprintf(listing, "Parameter: name = %s, type = ", tree->attr.name);
|
|
printType(tree);
|
|
fprintf(listing, "\n");
|
|
}
|
|
break;
|
|
case ArrParamK:
|
|
fprintf(listing, "Parameter: name = %s, type = ", tree->attr.name);
|
|
printType(tree);
|
|
fprintf(listing, "\n");
|
|
break;
|
|
default:
|
|
fprintf(listing, "Unknown DeclNode kind\n");
|
|
break;
|
|
}
|
|
} else if (tree->nodekind == TypeK) {
|
|
|
|
} else
|
|
fprintf(listing, "Unknown node kind\n");
|
|
for (i = 0; i < MAXCHILDREN; i++)
|
|
printTree(tree->child[i]);
|
|
tree = tree->sibling;
|
|
}
|
|
UNINDENT;
|
|
}
|