initial commit
This commit is contained in:
159
src/analyze.c
Normal file
159
src/analyze.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/****************************************************/
|
||||
/* File: analyze.c */
|
||||
/* Semantic analyzer implementation */
|
||||
/* for the TINY compiler */
|
||||
/* Compiler Construction: Principles and Practice */
|
||||
/* Kenneth C. Louden */
|
||||
/****************************************************/
|
||||
|
||||
#include "globals.h"
|
||||
#include "symtab.h"
|
||||
#include "analyze.h"
|
||||
|
||||
/* counter for variable memory locations */
|
||||
static int location = 0;
|
||||
|
||||
/* Procedure traverse is a generic recursive
|
||||
* syntax tree traversal routine:
|
||||
* it applies preProc in preorder and postProc
|
||||
* in postorder to tree pointed to by t
|
||||
*/
|
||||
static void traverse( TreeNode * t,
|
||||
void (* preProc) (TreeNode *),
|
||||
void (* postProc) (TreeNode *) )
|
||||
{ if (t != NULL)
|
||||
{ preProc(t);
|
||||
{ int i;
|
||||
for (i=0; i < MAXCHILDREN; i++)
|
||||
traverse(t->child[i],preProc,postProc);
|
||||
}
|
||||
postProc(t);
|
||||
traverse(t->sibling,preProc,postProc);
|
||||
}
|
||||
}
|
||||
|
||||
/* nullProc is a do-nothing procedure to
|
||||
* generate preorder-only or postorder-only
|
||||
* traversals from traverse
|
||||
*/
|
||||
static void nullProc(TreeNode * t)
|
||||
{ if (t==NULL) return;
|
||||
else return;
|
||||
}
|
||||
|
||||
/* Procedure insertNode inserts
|
||||
* identifiers stored in t into
|
||||
* the symbol table
|
||||
*/
|
||||
static void insertNode( TreeNode * t)
|
||||
{ switch (t->nodekind)
|
||||
{ case StmtK:
|
||||
switch (t->kind.stmt)
|
||||
{ case AssignK:
|
||||
case ReadK:
|
||||
if (st_lookup(t->attr.name) == -1)
|
||||
/* not yet in table, so treat as new definition */
|
||||
st_insert(t->attr.name,t->lineno,location++);
|
||||
else
|
||||
/* already in table, so ignore location,
|
||||
add line number of use only */
|
||||
st_insert(t->attr.name,t->lineno,0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ExpK:
|
||||
switch (t->kind.exp)
|
||||
{ case IdK:
|
||||
if (st_lookup(t->attr.name) == -1)
|
||||
/* not yet in table, so treat as new definition */
|
||||
st_insert(t->attr.name,t->lineno,location++);
|
||||
else
|
||||
/* already in table, so ignore location,
|
||||
add line number of use only */
|
||||
st_insert(t->attr.name,t->lineno,0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Function buildSymtab constructs the symbol
|
||||
* table by preorder traversal of the syntax tree
|
||||
*/
|
||||
void buildSymtab(TreeNode * syntaxTree)
|
||||
{ traverse(syntaxTree,insertNode,nullProc);
|
||||
if (TraceAnalyze)
|
||||
{ fprintf(listing,"\nSymbol table:\n\n");
|
||||
printSymTab(listing);
|
||||
}
|
||||
}
|
||||
|
||||
static void typeError(TreeNode * t, char * message)
|
||||
{ fprintf(listing,"Type error at line %d: %s\n",t->lineno,message);
|
||||
Error = TRUE;
|
||||
}
|
||||
|
||||
/* Procedure checkNode performs
|
||||
* type checking at a single tree node
|
||||
*/
|
||||
static void checkNode(TreeNode * t)
|
||||
{ switch (t->nodekind)
|
||||
{ case ExpK:
|
||||
switch (t->kind.exp)
|
||||
{ case OpK:
|
||||
if ((t->child[0]->type != Integer) ||
|
||||
(t->child[1]->type != Integer))
|
||||
typeError(t,"Op applied to non-integer");
|
||||
if ((t->attr.op == EQ) || (t->attr.op == LT))
|
||||
t->type = Boolean;
|
||||
else
|
||||
t->type = Integer;
|
||||
break;
|
||||
case ConstK:
|
||||
case IdK:
|
||||
t->type = Integer;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case StmtK:
|
||||
switch (t->kind.stmt)
|
||||
{ case IfK:
|
||||
if (t->child[0]->type == Integer)
|
||||
typeError(t->child[0],"if test is not Boolean");
|
||||
break;
|
||||
case AssignK:
|
||||
if (t->child[0]->type != Integer)
|
||||
typeError(t->child[0],"assignment of non-integer value");
|
||||
break;
|
||||
case WriteK:
|
||||
if (t->child[0]->type != Integer)
|
||||
typeError(t->child[0],"write of non-integer value");
|
||||
break;
|
||||
case RepeatK:
|
||||
if (t->child[1]->type == Integer)
|
||||
typeError(t->child[1],"repeat test is not Boolean");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Procedure typeCheck performs type checking
|
||||
* by a postorder syntax tree traversal
|
||||
*/
|
||||
void typeCheck(TreeNode * syntaxTree)
|
||||
{ traverse(syntaxTree,nullProc,checkNode);
|
||||
}
|
||||
Reference in New Issue
Block a user