semi-complete semantic
This commit is contained in:
29
src/Makefile
29
src/Makefile
@@ -1,34 +1,31 @@
|
|||||||
# Makefile for C-Minus
|
# Makefile for C-Minus
|
||||||
#
|
#
|
||||||
# ./lex/tiny.l --> ./cminus.l (from Project 1)
|
# ./lex/tiny.l --> ./cminus.l (from Project 1)
|
||||||
# ./yacc/tiny.y --> ./cminus.y
|
# ./yacc/tiny.y --> ./cminus.y (from Project 2)
|
||||||
# ./yacc/globals.h --> ./globals.h
|
# ./yacc/globals.h --> ./globals.h (from Project 2)
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
|
|
||||||
CFLAGS = -W -Wall
|
CFLAGS = -W -Wall -g
|
||||||
|
|
||||||
OBJS = main.o util.o lex.yy.o y.tab.o
|
OBJS = main.o util.o lex.yy.o y.tab.o symtab.o analyze.o
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
all: cminus_parser
|
all: cminus_semantic
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -vf cminus_parser *.o lex.yy.c y.tab.c y.tab.h y.output
|
rm -vf cminus_semantic *.o lex.yy.c y.tab.c y.tab.h y.output
|
||||||
|
|
||||||
cminus_parser: $(OBJS)
|
cminus_semantic: $(OBJS)
|
||||||
$(CC) $(CFLAGS) $(OBJS) -o $@ -lfl
|
$(CC) $(CFLAGS) $(OBJS) -o $@ -lfl
|
||||||
|
|
||||||
main.o: main.c globals.h util.h scan.h parse.h y.tab.h
|
main.o: main.c globals.h util.h scan.h parse.h y.tab.h analyze.h
|
||||||
$(CC) $(CFLAGS) -c main.c
|
$(CC) $(CFLAGS) -c main.c
|
||||||
|
|
||||||
util.o: util.c util.h globals.h y.tab.h
|
util.o: util.c util.h globals.h y.tab.h
|
||||||
$(CC) $(CFLAGS) -c util.c
|
$(CC) $(CFLAGS) -c util.c
|
||||||
|
|
||||||
scan.o: scan.c scan.h util.h globals.h y.tab.h
|
lex.yy.o: lex.yy.c scan.h globals.h y.tab.h util.h
|
||||||
$(CC) $(CFLAGS) -c scan.c
|
|
||||||
|
|
||||||
lex.yy.o: lex.yy.c scan.h util.h globals.h y.tab.h
|
|
||||||
$(CC) $(CFLAGS) -c lex.yy.c
|
$(CC) $(CFLAGS) -c lex.yy.c
|
||||||
|
|
||||||
lex.yy.c: cminus.l
|
lex.yy.c: cminus.l
|
||||||
@@ -40,4 +37,10 @@ y.tab.o: y.tab.c parse.h
|
|||||||
$(CC) $(CFLAGS) -c y.tab.c
|
$(CC) $(CFLAGS) -c y.tab.c
|
||||||
|
|
||||||
y.tab.c: cminus.y
|
y.tab.c: cminus.y
|
||||||
yacc -d -Wcounterexamples -v cminus.y
|
yacc -d -v cminus.y
|
||||||
|
|
||||||
|
analyze.o: analyze.c analyze.h globals.h y.tab.h symtab.h util.h
|
||||||
|
$(CC) $(CFLAGS) -c analyze.c
|
||||||
|
|
||||||
|
symtab.o: symtab.c symtab.h
|
||||||
|
$(CC) $(CFLAGS) -c symtab.c
|
||||||
|
|||||||
386
src/analyze.c
386
src/analyze.c
@@ -1,159 +1,315 @@
|
|||||||
/****************************************************/
|
/****************************************************/
|
||||||
/* File: analyze.c */
|
/* File: analyze.c */
|
||||||
/* Semantic analyzer implementation */
|
/* Semantic analyzer implementation */
|
||||||
/* for the TINY compiler */
|
/* for the CMinus compiler */
|
||||||
/* Compiler Construction: Principles and Practice */
|
/* Yenru0 */
|
||||||
/* Kenneth C. Louden */
|
|
||||||
/****************************************************/
|
/****************************************************/
|
||||||
|
|
||||||
|
#include "analyze.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "analyze.h"
|
|
||||||
|
|
||||||
/* counter for variable memory locations */
|
static void symbolError(TreeNode *t, char *message) {
|
||||||
static int location = 0;
|
fprintf(listing, "Symbol error at line %d: %s\n", t->lineno, message);
|
||||||
|
Error = TRUE;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BucketList func_entry = NULL;
|
||||||
|
static Scope func_scope;
|
||||||
|
static TreeNode *func_params[256];
|
||||||
|
static int func_param_count = 0;
|
||||||
|
|
||||||
/* Procedure traverse is a generic recursive
|
/* Procedure traverse is a generic recursive
|
||||||
* syntax tree traversal routine:
|
* syntax tree traversal routine:
|
||||||
* it applies preProc in preorder and postProc
|
* it applies preProc in preorder and postProc
|
||||||
* in postorder to tree pointed to by t
|
* in postorder to tree pointed to by t
|
||||||
*/
|
*/
|
||||||
static void traverse( TreeNode * t,
|
static void traverse(TreeNode *t,
|
||||||
void (* preProc) (TreeNode *),
|
void (*preProc)(TreeNode *),
|
||||||
void (* postProc) (TreeNode *) )
|
void (*postProc)(TreeNode *)) {
|
||||||
{ if (t != NULL)
|
if (t != NULL) {
|
||||||
{ preProc(t);
|
preProc(t);
|
||||||
{ int i;
|
{
|
||||||
for (i=0; i < MAXCHILDREN; i++)
|
int i;
|
||||||
traverse(t->child[i],preProc,postProc);
|
for (i = 0; i < MAXCHILDREN; i++)
|
||||||
|
traverse(t->child[i], preProc, postProc);
|
||||||
|
}
|
||||||
|
postProc(t);
|
||||||
|
traverse(t->sibling, preProc, postProc);
|
||||||
}
|
}
|
||||||
postProc(t);
|
|
||||||
traverse(t->sibling,preProc,postProc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* nullProc is a do-nothing procedure to
|
/* nullProc is a do-nothing procedure to
|
||||||
* generate preorder-only or postorder-only
|
* generate preorder-only or postorder-only
|
||||||
* traversals from traverse
|
* traversals from traverse
|
||||||
*/
|
*/
|
||||||
static void nullProc(TreeNode * t)
|
static void nullProc(TreeNode *t) {
|
||||||
{ if (t==NULL) return;
|
if (t == NULL) return;
|
||||||
else return;
|
else
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Procedure insertNode inserts
|
/* Procedure insertNode inserts
|
||||||
* identifiers stored in t into
|
* identifiers stored in t into
|
||||||
* the symbol table
|
* the symbol table
|
||||||
*/
|
*/
|
||||||
static void insertNode( TreeNode * t)
|
static void insertNode(TreeNode *t) {
|
||||||
{ switch (t->nodekind)
|
//printf("Insert Node: line %d\n", t->lineno);
|
||||||
{ case StmtK:
|
switch (t->nodekind) {
|
||||||
switch (t->kind.stmt)
|
case ExpK:
|
||||||
{ case AssignK:
|
switch (t->kind.exp) {
|
||||||
case ReadK:
|
case IdK:
|
||||||
if (st_lookup(t->attr.name) == -1)
|
case ArrIdK:
|
||||||
/* not yet in table, so treat as new definition */
|
case CallK: {
|
||||||
st_insert(t->attr.name,t->lineno,location++);
|
BucketList entry = st_lookup(t->attr.name);
|
||||||
else
|
if (entry == NULL) {
|
||||||
/* already in table, so ignore location,
|
symbolError(t, "Undeclared Symbol");
|
||||||
add line number of use only */
|
} else {
|
||||||
st_insert(t->attr.name,t->lineno,0);
|
// t->type = entry->type;// TODO: Ambiguity
|
||||||
break;
|
t->scope = curr_scope();
|
||||||
|
st_entry_insert_line(entry, t->lineno);
|
||||||
|
t->type = entry->type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case StmtK:
|
||||||
|
switch (t->kind.stmt) {
|
||||||
|
case CompK:
|
||||||
|
if (func_scope != NULL) {
|
||||||
|
push_scope(func_scope);
|
||||||
|
func_scope = NULL;
|
||||||
|
for (int i = 0; i < func_param_count; i++) {
|
||||||
|
TreeNode *param = func_params[i];
|
||||||
|
func_entry->param_types[func_entry->param_count++] = param->type;
|
||||||
|
if (st_lookup_current(param->attr.name) != NULL) {
|
||||||
|
symbolError(param, "Redefinition of a Parameter");
|
||||||
|
} else {
|
||||||
|
st_try_insert(param->attr.name, SymbolParam, param->type, param->lineno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func_entry = NULL;
|
||||||
|
func_scope = NULL;
|
||||||
|
func_param_count = 0;
|
||||||
|
} else {
|
||||||
|
push_scope(scope_new("compound"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeclK:
|
||||||
|
switch (t->kind.decl) {
|
||||||
|
case FuncK:
|
||||||
|
if (st_lookup(t->attr.name) != NULL) {
|
||||||
|
symbolError(t, "Redefinition of a Function");
|
||||||
|
} else {
|
||||||
|
func_entry = st_try_insert(t->attr.name, SymbolFunc, t->type, t->lineno);
|
||||||
|
t->scope = curr_scope();
|
||||||
|
}
|
||||||
|
|
||||||
|
func_scope = scope_new(t->attr.name);
|
||||||
|
//push_scope(scope_new(t->attr.name));
|
||||||
|
break;
|
||||||
|
case ArrParamK:
|
||||||
|
case NonArrParamK: {
|
||||||
|
|
||||||
|
if (t->type != Void) {
|
||||||
|
func_params[func_param_count++] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VarK:
|
||||||
|
case ArrVarK:
|
||||||
|
if (st_lookup_current(t->attr.name) != NULL) {
|
||||||
|
symbolError(t, "Redefinition of a Variable");
|
||||||
|
} else {
|
||||||
|
if (t->type == Void) {
|
||||||
|
symbolError(t, "Variable cannot be of type void");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t->scope = curr_scope();
|
||||||
|
st_try_insert(t->attr.name, SymbolVar, t->type, t->lineno);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case ExpK:
|
|
||||||
switch (t->kind.exp)
|
static void afterNode(TreeNode *t) {
|
||||||
{ case IdK:
|
if (t->nodekind == StmtK && t->kind.stmt == CompK) {
|
||||||
if (st_lookup(t->attr.name) == -1)
|
pop_scope();
|
||||||
/* 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
|
/* Function buildSymtab constructs the symbol
|
||||||
* table by preorder traversal of the syntax tree
|
* table by preorder traversal of the syntax tree
|
||||||
*/
|
*/
|
||||||
void buildSymtab(TreeNode * syntaxTree)
|
void buildSymtab(TreeNode *syntaxTree) {
|
||||||
{ traverse(syntaxTree,insertNode,nullProc);
|
st_init();
|
||||||
if (TraceAnalyze)
|
BucketList entry;
|
||||||
{ fprintf(listing,"\nSymbol table:\n\n");
|
entry = st_try_insert("input", SymbolFunc, Integer, 0);
|
||||||
printSymTab(listing);
|
entry->param_count = 0;
|
||||||
}
|
|
||||||
|
entry = st_try_insert("output", SymbolFunc, Void, 0);
|
||||||
|
entry->param_types[0] = Integer;
|
||||||
|
entry->param_count = 1;
|
||||||
|
|
||||||
|
traverse(syntaxTree, insertNode, afterNode);
|
||||||
|
if (TraceAnalyze) {
|
||||||
|
fprintf(listing, "\nSymbol table:\n\n");
|
||||||
|
printSymTab(listing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void typeError(TreeNode * t, char * message)
|
static void typeError(TreeNode *t, char *message) {
|
||||||
{ fprintf(listing,"Type error at line %d: %s\n",t->lineno,message);
|
fprintf(listing, "Type error at line %d: %s\n", t->lineno, message);
|
||||||
Error = TRUE;
|
Error = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Procedure checkNode performs
|
static void beforeCheckNode(TreeNode *t) {
|
||||||
* type checking at a single tree node
|
if (t->nodekind == DeclK && t->kind.decl == FuncK) {
|
||||||
*/
|
func_entry = st_lookup(t->attr.name);
|
||||||
static void checkNode(TreeNode * t)
|
}
|
||||||
{ switch (t->nodekind)
|
}
|
||||||
{ case ExpK:
|
static void checkNode(TreeNode *t) {
|
||||||
switch (t->kind.exp)
|
switch (t->nodekind) {
|
||||||
{ case OpK:
|
case ExpK:
|
||||||
if ((t->child[0]->type != Integer) ||
|
switch (t->kind.exp) {
|
||||||
(t->child[1]->type != Integer))
|
case OpK: {
|
||||||
typeError(t,"Op applied to non-integer");
|
TreeNode *left = t->child[0];
|
||||||
if ((t->attr.op == EQ) || (t->attr.op == LT))
|
TreeNode *right = t->child[1];
|
||||||
t->type = Boolean;
|
if (left->type != Integer || right->type != Integer) {
|
||||||
else
|
typeError(t, "Operator applied to non-integer");
|
||||||
t->type = Integer;
|
}
|
||||||
break;
|
t->type = Integer;
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
} break;
|
||||||
|
case ConstK:
|
||||||
|
t->type = Integer;
|
||||||
|
break;
|
||||||
|
case IdK: {
|
||||||
|
BucketList entry = st_lookup_from(t->attr.name, t->scope);
|
||||||
|
t->type = entry->type;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case ArrIdK: {
|
||||||
|
if (t->child[0]->type != Integer) {
|
||||||
|
typeError(t, "Array subscript is not an integer");
|
||||||
|
}
|
||||||
|
t->type = IntegerArray;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case AssignK: {
|
||||||
|
TreeNode *left = t->child[0];
|
||||||
|
TreeNode *right = t->child[1];
|
||||||
|
if (left->type != right->type) {
|
||||||
|
typeError(t, "Assignment of different types");
|
||||||
|
}
|
||||||
|
t->type = left->type;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case CallK: {
|
||||||
|
BucketList entry = st_lookup_from(t->attr.name, t->scope);// not null
|
||||||
|
|
||||||
|
if (entry->symbolKind != SymbolFunc) {
|
||||||
|
typeError(t, "Call to a non-function");
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *arg = t->child[0];
|
||||||
|
|
||||||
|
int i = 0;// 파라미터 인덱스
|
||||||
|
|
||||||
|
while (arg != NULL && i < entry->param_count) {
|
||||||
|
if (arg->type != entry->param_types[i]) {
|
||||||
|
typeError(t, "Type mismatch in argument: Expected different type");
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = arg->sibling;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg != NULL) {
|
||||||
|
typeError(t, "Too many arguments in function call");
|
||||||
|
} else if (i < entry->param_count) {
|
||||||
|
typeError(t, "Too few arguments in function call");
|
||||||
|
}
|
||||||
|
|
||||||
|
t->type = entry->returnType;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case StmtK:
|
||||||
|
switch (t->kind.stmt) {
|
||||||
|
case ReturnK: {
|
||||||
|
|
||||||
|
if (func_entry == NULL) {
|
||||||
|
typeError(t, "Return statement is not in a function");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TreeNode *retval = t->child[0]; /* nullalbe */
|
||||||
|
if (func_entry->returnType == Void) {
|
||||||
|
if (retval != NULL) {
|
||||||
|
typeError(t, "Return with a value in a void function");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (retval == NULL) {
|
||||||
|
typeError(t, "Return without a value in a non-void function");
|
||||||
|
} else if (retval->type != func_entry->returnType) {
|
||||||
|
typeError(t, "Return type mismatch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case IterK: {
|
||||||
|
TreeNode *condition = t->child[0];
|
||||||
|
if (condition->type != Integer) {
|
||||||
|
typeError(t, "While condition is not of type integer");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case IfK: {
|
||||||
|
TreeNode *condition = t->child[0];
|
||||||
|
if (condition->type != Integer) {
|
||||||
|
typeError(t, "If condition is not of type integer");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeclK:
|
||||||
|
switch (t->kind.decl) {
|
||||||
|
|
||||||
|
case FuncK:
|
||||||
|
func_entry = NULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Procedure typeCheck performs type checking
|
/* Procedure typeCheck performs type checking
|
||||||
* by a postorder syntax tree traversal
|
* by a postorder syntax tree traversal
|
||||||
*/
|
*/
|
||||||
void typeCheck(TreeNode * syntaxTree)
|
void typeCheck(TreeNode *syntaxTree) {
|
||||||
{ traverse(syntaxTree,nullProc,checkNode);
|
traverse(syntaxTree, beforeCheckNode, checkNode);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
struct Scope;
|
||||||
|
typedef struct Scope *Scope;
|
||||||
|
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE 0
|
#define FALSE 0
|
||||||
#endif
|
#endif
|
||||||
@@ -103,7 +106,14 @@ typedef enum { TypeNameK } TypeKind;
|
|||||||
/* ExpType is used for type checking */
|
/* ExpType is used for type checking */
|
||||||
typedef enum { Void,
|
typedef enum { Void,
|
||||||
Integer,
|
Integer,
|
||||||
IntegerArray } ExpType;
|
IntegerArray
|
||||||
|
} ExpType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SymbolVar,
|
||||||
|
SymbolFunc,
|
||||||
|
SymbolParam
|
||||||
|
} SymbolKind;
|
||||||
|
|
||||||
#define MAXCHILDREN 3
|
#define MAXCHILDREN 3
|
||||||
|
|
||||||
@@ -124,6 +134,7 @@ typedef struct treeNode {
|
|||||||
char *name;
|
char *name;
|
||||||
} attr;
|
} attr;
|
||||||
ExpType type; /* for type checking of exps */
|
ExpType type; /* for type checking of exps */
|
||||||
|
Scope scope;
|
||||||
} TreeNode;
|
} TreeNode;
|
||||||
|
|
||||||
/**************************************************/
|
/**************************************************/
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
/* set NO_PARSE to TRUE to get a scanner-only compiler */
|
/* set NO_PARSE to TRUE to get a scanner-only compiler */
|
||||||
#define NO_PARSE FALSE
|
#define NO_PARSE FALSE
|
||||||
/* set NO_ANALYZE to TRUE to get a parser-only compiler */
|
/* set NO_ANALYZE to TRUE to get a parser-only compiler */
|
||||||
#define NO_ANALYZE TRUE
|
#define NO_ANALYZE FALSE
|
||||||
|
|
||||||
/* set NO_CODE to TRUE to get a compiler that does not
|
/* set NO_CODE to TRUE to get a compiler that does not
|
||||||
* generate code
|
* generate code
|
||||||
@@ -40,7 +40,7 @@ FILE *code;
|
|||||||
int EchoSource = FALSE;
|
int EchoSource = FALSE;
|
||||||
int TraceScan = FALSE;
|
int TraceScan = FALSE;
|
||||||
int TraceParse = TRUE;
|
int TraceParse = TRUE;
|
||||||
int TraceAnalyze = FALSE;
|
int TraceAnalyze = TRUE;
|
||||||
int TraceCode = FALSE;
|
int TraceCode = FALSE;
|
||||||
|
|
||||||
int Error = FALSE;
|
int Error = FALSE;
|
||||||
|
|||||||
245
src/symtab.c
245
src/symtab.c
@@ -4,8 +4,6 @@
|
|||||||
/* (allows only one symbol table) */
|
/* (allows only one symbol table) */
|
||||||
/* Symbol table is implemented as a chained */
|
/* Symbol table is implemented as a chained */
|
||||||
/* hash table */
|
/* hash table */
|
||||||
/* Compiler Construction: Principles and Practice */
|
|
||||||
/* Kenneth C. Louden */
|
|
||||||
/****************************************************/
|
/****************************************************/
|
||||||
|
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
@@ -13,6 +11,17 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
Scope scope_stack[MAX_SCOPE_DEPTH];
|
||||||
|
int scope_stack_top = -1;
|
||||||
|
Scope scope_global;// no sibling no parent
|
||||||
|
|
||||||
|
void st_init(void) {
|
||||||
|
scope_global = scope_new("global");
|
||||||
|
scope_global->depth = 0;
|
||||||
|
scope_stack_top = 0;
|
||||||
|
scope_stack[scope_stack_top] = scope_global;
|
||||||
|
}
|
||||||
|
|
||||||
/* SHIFT is the power of two used as multiplier
|
/* SHIFT is the power of two used as multiplier
|
||||||
in hash function */
|
in hash function */
|
||||||
#define SHIFT 4
|
#define SHIFT 4
|
||||||
@@ -28,79 +37,213 @@ static int hash(char *key) {
|
|||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope curr_scope(void) {
|
Scope scope_new(char *scope_name) {// it
|
||||||
if (top_stack == -1) {
|
Scope new_scope = (Scope) malloc(sizeof(struct Scope));
|
||||||
return NULL;
|
new_scope->name = scope_name;
|
||||||
|
new_scope->depth = -1;
|
||||||
|
new_scope->parent = NULL;
|
||||||
|
new_scope->child = NULL;
|
||||||
|
new_scope->child_last = NULL;
|
||||||
|
new_scope->next_sibling = NULL;
|
||||||
|
|
||||||
|
new_scope->location = 0;
|
||||||
|
return new_scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_scope(void) {
|
||||||
|
if (scope_stack_top == -1) {// empty
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
return scope_stack[top_stack];
|
scope_stack[scope_stack_top] = NULL;
|
||||||
|
scope_stack_top--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Procedure st_insert inserts line numbers and
|
void push_scope(Scope scope) {
|
||||||
* memory locations into the symbol table
|
if (scope_stack_top == MAX_SCOPE_DEPTH - 1) {// full
|
||||||
* loc = memory location is inserted only the
|
return;
|
||||||
* first time, otherwise ignored
|
} else {
|
||||||
*/
|
Scope before = curr_scope();
|
||||||
void st_insert(char *name, int lineno, int loc) {
|
if (before->child == NULL) {
|
||||||
|
before->child = scope;
|
||||||
|
before->child_last = scope;
|
||||||
|
} else {
|
||||||
|
before->child_last->next_sibling = scope;
|
||||||
|
before->child_last = scope;
|
||||||
|
}
|
||||||
|
scope->parent = before;
|
||||||
|
scope->depth = before->depth + 1;
|
||||||
|
|
||||||
|
scope_stack_top++;
|
||||||
|
scope_stack[scope_stack_top] = scope;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope curr_scope(void) {
|
||||||
|
if (scope_stack_top == -1) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return scope_stack[scope_stack_top];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BucketList st_try_insert(char *name, SymbolKind symbolkind, ExpType type, int lineno) {
|
||||||
int h = hash(name);
|
int h = hash(name);
|
||||||
|
Scope scope = curr_scope();
|
||||||
|
BucketList *hashTable = scope->hashTable;
|
||||||
BucketList l = hashTable[h];
|
BucketList l = hashTable[h];
|
||||||
while ((l != NULL) && (strcmp(name, l->name) != 0))
|
while ((l != NULL) && (strcmp(name, l->name) != 0))
|
||||||
l = l->next;
|
l = l->next;
|
||||||
if (l == NULL) /* variable not yet in table */
|
if (l == NULL) { /* variable not yet in table */
|
||||||
{
|
l = (BucketList) malloc(sizeof(struct BucketListEntry));
|
||||||
l = (BucketList) malloc(sizeof(struct BucketListRec));
|
|
||||||
l->name = name;
|
l->name = name;
|
||||||
l->lines = (LineList) malloc(sizeof(struct LineListRec));
|
l->symbolKind = symbolkind;
|
||||||
|
l->lines = (LineList) malloc(sizeof(struct LineListEntry));
|
||||||
l->lines->lineno = lineno;
|
l->lines->lineno = lineno;
|
||||||
l->memloc = loc;
|
l->symbolKind = symbolkind;
|
||||||
|
if (symbolkind == SymbolFunc) {
|
||||||
|
l->type = Void;
|
||||||
|
l->returnType = type;
|
||||||
|
l->param_count = 0;
|
||||||
|
} else {
|
||||||
|
l->type = type;
|
||||||
|
l->returnType = type;
|
||||||
|
}
|
||||||
|
|
||||||
l->lines->next = NULL;
|
l->lines->next = NULL;
|
||||||
|
l->memloc = scope->location;
|
||||||
|
scope->location++;
|
||||||
l->next = hashTable[h];
|
l->next = hashTable[h];
|
||||||
hashTable[h] = l;
|
hashTable[h] = l;
|
||||||
} else /* found in table, so just add line number */
|
} else { /* found in table, so just add line number */
|
||||||
{
|
|
||||||
LineList t = l->lines;
|
LineList t = l->lines;
|
||||||
while (t->next != NULL) t = t->next;
|
while (t->next != NULL)
|
||||||
t->next = (LineList) malloc(sizeof(struct LineListRec));
|
t = t->next;
|
||||||
|
t->next = (LineList) malloc(sizeof(struct LineListEntry));
|
||||||
t->next->lineno = lineno;
|
t->next->lineno = lineno;
|
||||||
t->next->next = NULL;
|
t->next->next = NULL;
|
||||||
}
|
}
|
||||||
} /* st_insert */
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
/* Function st_lookup returns the memory
|
void st_entry_insert_line(BucketList entry, int lineno) {
|
||||||
* location of a variable or -1 if not found
|
if (entry == NULL) return;
|
||||||
*/
|
LineList t = entry->lines;
|
||||||
int st_lookup(char *name) {
|
while (t->next != NULL)
|
||||||
|
t = t->next;
|
||||||
|
t->next = (LineList) malloc(sizeof(struct LineListEntry));
|
||||||
|
t->next->lineno = lineno;
|
||||||
|
t->next->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
BucketList st_lookup_current(char *name) {
|
||||||
int h = hash(name);
|
int h = hash(name);
|
||||||
|
Scope scope = curr_scope();
|
||||||
|
BucketList *hashTable = scope->hashTable;
|
||||||
BucketList l = hashTable[h];
|
BucketList l = hashTable[h];
|
||||||
while ((l != NULL) && (strcmp(name, l->name) != 0))
|
while ((l != NULL) && (strcmp(name, l->name) != 0))
|
||||||
l = l->next;
|
l = l->next;
|
||||||
if (l == NULL) return -1;
|
|
||||||
else
|
return l;
|
||||||
return l->memloc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Procedure printSymTab prints a formatted
|
BucketList st_lookup(char *name) {
|
||||||
* listing of the symbol table contents
|
int h = hash(name);
|
||||||
* to the listing file
|
Scope scope = curr_scope();
|
||||||
*/
|
while (scope != NULL) {
|
||||||
void printSymTab(FILE *listing) {
|
BucketList *hashTable = scope->hashTable;
|
||||||
int i;
|
BucketList l = hashTable[h];
|
||||||
fprintf(listing, "Variable Name Location Line Numbers\n");
|
while ((l != NULL) && (strcmp(name, l->name) != 0))
|
||||||
fprintf(listing, "------------- -------- ------------\n");
|
l = l->next;
|
||||||
for (i = 0; i < SYMTAB_SIZE; ++i) {
|
if (l != NULL) {
|
||||||
if (hashTable[i] != NULL) {
|
return l;
|
||||||
BucketList l = hashTable[i];
|
}
|
||||||
while (l != NULL) {
|
scope = scope->parent;
|
||||||
LineList t = l->lines;
|
}
|
||||||
fprintf(listing, "%-14s ", l->name);
|
return NULL; /* not found */
|
||||||
fprintf(listing, "%-8d ", l->memloc);
|
}
|
||||||
while (t != NULL) {
|
|
||||||
fprintf(listing, "%4d ", t->lineno);
|
BucketList st_lookup_from(char *name, Scope scope) {
|
||||||
t = t->next;
|
int h = hash(name);
|
||||||
}
|
while (scope != NULL) {
|
||||||
fprintf(listing, "\n");
|
BucketList *hashTable = scope->hashTable;
|
||||||
l = l->next;
|
BucketList l = hashTable[h];
|
||||||
|
while ((l != NULL) && (strcmp(name, l->name) != 0))
|
||||||
|
l = l->next;
|
||||||
|
if (l != NULL) {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
scope = scope->parent;
|
||||||
|
}
|
||||||
|
return NULL; /* not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
void printScope(FILE *listing, Scope scope) {
|
||||||
|
if (scope == NULL) return;
|
||||||
|
fprintf(listing, "Scope Name: %s, Depth: %d\n", scope->name, scope->depth);
|
||||||
|
fprintf(listing, "-----------------------------------------\n");
|
||||||
|
fprintf(listing, "Variable Name Symbol Kind Type Location Line Numbers\n");
|
||||||
|
fprintf(listing, "------------------------------------------------------------\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < SYMTAB_SIZE; i++) {
|
||||||
|
BucketList l = scope->hashTable[i];
|
||||||
|
while (l != NULL) {
|
||||||
|
fprintf(listing, "%-14s", l->name);
|
||||||
|
switch (l->symbolKind) {
|
||||||
|
case SymbolVar:
|
||||||
|
fprintf(listing, "%-13s", "Variable");
|
||||||
|
break;
|
||||||
|
case SymbolFunc:
|
||||||
|
fprintf(listing, "%-13s", "Function");
|
||||||
|
break;
|
||||||
|
case SymbolParam:
|
||||||
|
fprintf(listing, "%-13s", "Parameter");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
switch (l->type) {
|
||||||
|
case Void:
|
||||||
|
fprintf(listing, "%-11s", "void");
|
||||||
|
break;
|
||||||
|
case Integer:
|
||||||
|
fprintf(listing, "%-11s", "int");
|
||||||
|
break;
|
||||||
|
case IntegerArray:
|
||||||
|
fprintf(listing, "%-11s", "int[]");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fprintf(listing, "%-9d", l->memloc);
|
||||||
|
LineList t = l->lines;
|
||||||
|
while (t != NULL) {
|
||||||
|
fprintf(listing, "%d ", t->lineno);
|
||||||
|
t = t->next;
|
||||||
|
}
|
||||||
|
fprintf(listing, "\n");
|
||||||
|
l = l->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} /* printSymTab */
|
fprintf(listing, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printScopeRecursive(FILE *listing, Scope scope) {
|
||||||
|
if (scope == NULL) return;
|
||||||
|
|
||||||
|
printScope(listing, scope);
|
||||||
|
|
||||||
|
Scope child = scope->child;
|
||||||
|
while (child != NULL) {
|
||||||
|
printScopeRecursive(listing, child);
|
||||||
|
child = child->next_sibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printScopeTree(FILE *listing) {
|
||||||
|
if (scope_global == NULL) return;
|
||||||
|
|
||||||
|
Scope current_scope = scope_global;
|
||||||
|
|
||||||
|
printScopeRecursive(listing, current_scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printSymTab(FILE *listing) {
|
||||||
|
printScopeTree(listing);
|
||||||
|
}
|
||||||
|
|||||||
90
src/symtab.h
90
src/symtab.h
@@ -9,16 +9,23 @@
|
|||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
/* SYMTAB_SIZE is the size of the hash table */
|
/**
|
||||||
|
* it is the size of the hash table
|
||||||
|
*/
|
||||||
#define SYMTAB_SIZE 211
|
#define SYMTAB_SIZE 211
|
||||||
|
|
||||||
|
#define MAX_SCOPE_DEPTH 32
|
||||||
|
#define MAX_SCOPE_COUNT 1557
|
||||||
|
|
||||||
|
#define MAX_PARAM_COUNT 13
|
||||||
|
|
||||||
/* the list of line numbers of the source
|
/* the list of line numbers of the source
|
||||||
* code in which a variable is referenced
|
* code in which a variable is referenced
|
||||||
*/
|
*/
|
||||||
typedef struct LineListEntry {
|
typedef struct LineListEntry {
|
||||||
int lineno;
|
int lineno;
|
||||||
struct LineListEntry *next;
|
struct LineListEntry *next;
|
||||||
} *LineList;
|
} * LineList;
|
||||||
|
|
||||||
/* The record in the bucket lists for
|
/* The record in the bucket lists for
|
||||||
* each variable, including name,
|
* each variable, including name,
|
||||||
@@ -29,61 +36,80 @@ typedef struct LineListEntry {
|
|||||||
typedef struct BucketListEntry {
|
typedef struct BucketListEntry {
|
||||||
char *name;
|
char *name;
|
||||||
LineList lines;
|
LineList lines;
|
||||||
|
SymbolKind symbolKind;
|
||||||
|
|
||||||
ExpType type;
|
ExpType type;
|
||||||
|
ExpType param_types[MAX_PARAM_COUNT];
|
||||||
|
int param_count;
|
||||||
|
ExpType returnType;
|
||||||
|
|
||||||
int memloc; /* memory location for variable */
|
int memloc; /* memory location for variable */
|
||||||
struct BucketListEntry *next;
|
struct BucketListEntry *next;
|
||||||
} *BucketList;
|
} * BucketList;
|
||||||
|
|
||||||
typedef struct Scope {
|
struct Scope {
|
||||||
char *name;
|
char *name;
|
||||||
int depth;
|
int depth;
|
||||||
|
|
||||||
struct Scope *parent;
|
struct Scope *parent;
|
||||||
|
struct Scope *child;
|
||||||
|
struct Scope *child_last;
|
||||||
|
struct Scope *next_sibling;
|
||||||
|
|
||||||
|
int location;
|
||||||
BucketList hashTable[SYMTAB_SIZE];
|
BucketList hashTable[SYMTAB_SIZE];
|
||||||
} *Scope;
|
};
|
||||||
|
|
||||||
Scope scope_global;
|
extern Scope scope_global;// no sibling no parent
|
||||||
|
|
||||||
static Scope scope_list[SYMTAB_SIZE];
|
extern Scope scope_stack[MAX_SCOPE_DEPTH];
|
||||||
static int size_list = 0;
|
extern int scope_stack_top;
|
||||||
|
|
||||||
static Scope scope_stack[SYMTAB_SIZE];
|
/**
|
||||||
static int top_stack = -1;
|
* before using the symbol table, initialize the global scope
|
||||||
|
*/
|
||||||
|
void st_init(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create a new scope with given name
|
* create a new scope with given name
|
||||||
|
* @note it does not link parent or insert into stack/list
|
||||||
* @param scope_name: name of the scope
|
* @param scope_name: name of the scope
|
||||||
* @return the created scope
|
* @return the created scope
|
||||||
*/
|
*/
|
||||||
Scope scope_new(char *scope_name);
|
Scope scope_new(char *scope_name);
|
||||||
/**
|
/**
|
||||||
* pop the current scope from the scope stack
|
* pop the current scope from the scope stack
|
||||||
*/
|
*/
|
||||||
void pop_scope(void);
|
void pop_scope(void);
|
||||||
/**
|
/**
|
||||||
* push a scope into the scope stack
|
* push a scope into the scope stack
|
||||||
|
* @note it does link the parent or siblings to construct tree
|
||||||
* @param scope: the scope to be pushed
|
* @param scope: the scope to be pushed
|
||||||
*/
|
*/
|
||||||
void push_scope(Scope scope);
|
void push_scope(Scope scope);
|
||||||
/**
|
/**
|
||||||
* insert a scope into the scope list
|
* get the top of the scope stack wit
|
||||||
*/
|
|
||||||
void insert_scope_to_list(Scope scope);
|
|
||||||
/**
|
|
||||||
* get the top of the scope stack
|
|
||||||
* @return the current scope or NULL if the stack is empty
|
* @return the current scope or NULL if the stack is empty
|
||||||
*/
|
*/
|
||||||
Scope curr_scope(void);
|
Scope curr_scope(void);
|
||||||
/**
|
/**
|
||||||
* insert a variable into the symbol table
|
* insert a variable into the symbol table of the current scope
|
||||||
* or update a variable if it already exists
|
* or add a line number if it already exists
|
||||||
* @param scope_name name of the scope
|
|
||||||
* @param name name of the variable
|
* @param name name of the variable
|
||||||
|
* @param symbolkind kind of the symbol
|
||||||
* @param type type of the variable
|
* @param type type of the variable
|
||||||
* @param lineno line number of the variable
|
* @param lineno line number of the variable
|
||||||
* @param loc memory location of the variable
|
|
||||||
* @return 0 if success, -1 if failure
|
* @return 0 if success, -1 if failure
|
||||||
*/
|
*/
|
||||||
int st_try_insert(char *name, ExpType type, int loc);
|
BucketList st_try_insert(char *name, SymbolKind symbolkind, ExpType type, int lineno);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insert a line number into the variable's line list
|
||||||
|
* @param entry the bucket list entry of the variable
|
||||||
|
* @param lineno the line number to be inserted
|
||||||
|
*/
|
||||||
|
void st_entry_insert_line(BucketList entry, int lineno);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lookup a variable in the current scope
|
* lookup a variable in the current scope
|
||||||
* @param name name of the variable to lookup
|
* @param name name of the variable to lookup
|
||||||
@@ -91,22 +117,24 @@ int st_try_insert(char *name, ExpType type, int loc);
|
|||||||
*/
|
*/
|
||||||
BucketList st_lookup_current(char *name);
|
BucketList st_lookup_current(char *name);
|
||||||
/**
|
/**
|
||||||
* lookup a variable from the given scope to root
|
* lookup a variable from the top scope to root
|
||||||
* @param name name of the variable to lookup
|
* @param name name of the variable to lookup
|
||||||
* @return the bucket list entry of the variable or NULL if not found
|
* @return the bucket list entry of the variable or NULL if not found
|
||||||
*/
|
*/
|
||||||
BucketList st_lookup(char *name);
|
BucketList st_lookup(char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find a scope from the scope list
|
* lookup a variable from the given scope to root
|
||||||
* @param scope_name name of the scope to find
|
* @param name name of the variable to lookup
|
||||||
* @return the scope or NULL if not found
|
* @param scope the scope to start lookup from
|
||||||
*/
|
* @return the bucket list entry of the variable or NULL if not found
|
||||||
Scope find_scope(char *scope_name);
|
|
||||||
/**
|
|
||||||
* Procedure printSymTab prints a formatted
|
|
||||||
* listing of the symbol table contents
|
|
||||||
* to the listing file
|
|
||||||
*/
|
*/
|
||||||
|
BucketList st_lookup_from(char *name, Scope scope);
|
||||||
|
|
||||||
|
void printScope(FILE *listing, Scope scope);
|
||||||
|
|
||||||
|
void printScopeTree(FILE *listing);
|
||||||
|
|
||||||
void printSymTab(FILE *listing);
|
void printSymTab(FILE *listing);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
13
src/test.cm
Normal file
13
src/test.cm
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
int fib(int n) {
|
||||||
|
if (n <= 0) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return fib(n * fib(n - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int x;
|
||||||
|
x = fib(input());
|
||||||
|
output(x);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user