204 main.c
@@ -1,102 +1,102 @@
/****************************************************/
/* File: main.c */
/* Main program for TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/

#include "globals.h"

/* set NO_PARSE to TRUE to get a scanner-only compiler */
#define NO_PARSE TRUE
/* set NO_ANALYZE to TRUE to get a parser-only compiler */
#define NO_ANALYZE TRUE

/* set NO_CODE to TRUE to get a compiler that does not
* generate code
*/
#define NO_CODE TRUE

#include "util.h"
#if NO_PARSE
#include "scan.h"
#else
#include "parse.h"
#if !NO_ANALYZE
#include "analyze.h"
#if !NO_CODE
#include "cgen.h"
#endif
#endif
#endif

/* allocate global variables */
int lineno = 0;
FILE * source;
FILE * listing;
FILE * code;

/* allocate and set tracing flags */
int EchoSource = TRUE;
int TraceScan = TRUE;
int TraceParse = FALSE;
int TraceAnalyze = FALSE;
int TraceCode = FALSE;

int Error = FALSE;

int main( int argc, char * argv[] )
{ TreeNode * syntaxTree;
char pgm[120]; /* source code file name */
if (argc != 2)
{ fprintf(stderr,"usage: %s <filename>\n",argv[0]);
exit(1);
}
strcpy(pgm,argv[1]) ;
if (strchr (pgm, '.') == NULL)
strcat(pgm,".cminus");
source = fopen(pgm,"r");
if (source==NULL)
{ fprintf(stderr,"File %s not found\n",pgm);
exit(1);
}
listing = stdout; /* send listing to screen */
fprintf(listing,"\nTINY COMPILATION: %s\n",pgm);
#if NO_PARSE
while (getToken()!=ENDFILE);
#else
syntaxTree = parse();
if (TraceParse) {
fprintf(listing,"\nSyntax tree:\n");
printTree(syntaxTree);
}
#if !NO_ANALYZE
if (! Error)
{ if (TraceAnalyze) fprintf(listing,"\nBuilding Symbol Table...\n");
buildSymtab(syntaxTree);
if (TraceAnalyze) fprintf(listing,"\nChecking Types...\n");
typeCheck(syntaxTree);
if (TraceAnalyze) fprintf(listing,"\nType Checking Finished\n");
}
#if !NO_CODE
if (! Error)
{ char * codefile;
int fnlen = strcspn(pgm,".");
codefile = (char *) calloc(fnlen+4, sizeof(char));
strncpy(codefile,pgm,fnlen);
strcat(codefile,".tm");
code = fopen(codefile,"w");
if (code == NULL)
{ printf("Unable to open %s\n",codefile);
exit(1);
}
codeGen(syntaxTree,codefile);
fclose(code);
}
#endif
#endif
#endif
fclose(source);
return 0;
}

/****************************************************/
/* File: main.c */
/* Main program for TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/

#include "globals.h"

/* set NO_PARSE to TRUE to get a scanner-only compiler */
#define NO_PARSE TRUE
/* set NO_ANALYZE to TRUE to get a parser-only compiler */
#define NO_ANALYZE TRUE

/* set NO_CODE to TRUE to get a compiler that does not
* generate code
*/
#define NO_CODE TRUE

#include "util.h"
#if NO_PARSE
#include "scan.h"
#else
#include "parse.h"
#if !NO_ANALYZE
#include "analyze.h"
#if !NO_CODE
#include "cgen.h"
#endif
#endif
#endif

/* allocate global variables */
int lineno = 0;
FILE * source;
FILE * listing;
FILE * code;

/* allocate and set tracing flags */
int EchoSource = TRUE;
int TraceScan = TRUE;
int TraceParse = FALSE;
int TraceAnalyze = FALSE;
int TraceCode = FALSE;

int Error = FALSE;

int main( int argc, char * argv[] )
{ TreeNode * syntaxTree;
char pgm[120]; /* source code file name */
if (argc != 2)
{ fprintf(stderr,"usage: %s <filename>\n",argv[0]);
exit(1);
}
strcpy(pgm,argv[1]) ;
if (strchr (pgm, '.') == NULL)
strcat(pgm,".cminus");
source = fopen(pgm,"r");
if (source==NULL)
{ fprintf(stderr,"File %s not found\n",pgm);
exit(1);
}
listing = stdout; /* send listing to screen */
fprintf(listing,"\nTINY COMPILATION: %s\n",pgm);
#if NO_PARSE
while (getToken()!=ENDFILE);
#else
syntaxTree = parse();
if (TraceParse) {
fprintf(listing,"\nSyntax tree:\n");
printTree(syntaxTree);
}
#if !NO_ANALYZE
if (! Error)
{ if (TraceAnalyze) fprintf(listing,"\nBuilding Symbol Table...\n");
buildSymtab(syntaxTree);
if (TraceAnalyze) fprintf(listing,"\nChecking Types...\n");
typeCheck(syntaxTree);
if (TraceAnalyze) fprintf(listing,"\nType Checking Finished\n");
}
#if !NO_CODE
if (! Error)
{ char * codefile;
int fnlen = strcspn(pgm,".");
codefile = (char *) calloc(fnlen+4, sizeof(char));
strncpy(codefile,pgm,fnlen);
strcat(codefile,".tm");
code = fopen(codefile,"w");
if (code == NULL)
{ printf("Unable to open %s\n",codefile);
exit(1);
}
codeGen(syntaxTree,codefile);
fclose(code);
}
#endif
#endif
#endif
fclose(source);
return 0;
}

44 scan.h
@@ -1,22 +1,22 @@
/****************************************************/
/* File: scan.h */
/* The scanner interface for the TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/

#ifndef _SCAN_H_
#define _SCAN_H_

/* MAXTOKENLEN is the maximum size of a token */
#define MAXTOKENLEN 40

/* tokenString array stores the lexeme of each token */
extern char tokenString[MAXTOKENLEN+1];

/* function getToken returns the
* next token in source file
*/
TokenType getToken(void);

#endif
/****************************************************/
/* File: scan.h */
/* The scanner interface for the TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/

#ifndef _SCAN_H_
#define _SCAN_H_

/* MAXTOKENLEN is the maximum size of a token */
#define MAXTOKENLEN 40

/* tokenString array stores the lexeme of each token */
extern char tokenString[MAXTOKENLEN+1];

/* function getToken returns the
* next token in source file
*/
TokenType getToken(void);

#endif
368 util.c
@@ -1,184 +1,184 @@
/****************************************************/
/* File: util.c */
/* Utility function implementation */
/* for the TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/

#include "globals.h"
#include "util.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 VOID:
case INT:
case RETURN:
case WHILE:
fprintf(listing,
"reserved word: %s\n",tokenString);
break;
case ASSIGN: fprintf(listing,"=\n"); break;
case LT: fprintf(listing,"<\n"); break;
case LET: fprintf(listing,"<=\n"); break;
case GT: fprintf(listing,">\n"); break;
case GET: fprintf(listing,">=\n"); break;
case EQ: fprintf(listing,"==\n"); break;
case NEQ: fprintf(listing,"!=\n"); break;
case LPAREN: fprintf(listing,"(\n"); break;
case RPAREN: fprintf(listing,")\n"); break;
case LBRACKET: fprintf(listing,"[\n"); break;
case RBRACKET: fprintf(listing,"]\n"); break;
case LBRACE: fprintf(listing,"{\n"); break;
case RBRACE: fprintf(listing,"}\n"); break;
case SEMI: 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 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;
}

/* 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," ");
}

/* 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 IfK:
fprintf(listing,"If\n");
break;
case RepeatK:
fprintf(listing,"Repeat\n");
break;
case AssignK:
fprintf(listing,"Assign to: %s\n",tree->attr.name);
break;
case ReadK:
fprintf(listing,"Read: %s\n",tree->attr.name);
break;
case WriteK:
fprintf(listing,"Write\n");
break;
default:
fprintf(listing,"Unknown ExpNode kind\n");
break;
}
}
else if (tree->nodekind==ExpK)
{ switch (tree->kind.exp) {
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,"Id: %s\n",tree->attr.name);
break;
default:
fprintf(listing,"Unknown ExpNode kind\n");
break;
}
}
else fprintf(listing,"Unknown node kind\n");
for (i=0;i<MAXCHILDREN;i++)
printTree(tree->child[i]);
tree = tree->sibling;
}
UNINDENT;
}
/****************************************************/
/* File: util.c */
/* Utility function implementation */
/* for the TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/

#include "globals.h"
#include "util.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 VOID:
case INT:
case RETURN:
case WHILE:
fprintf(listing,
"reserved word: %s\n",tokenString);
break;
case ASSIGN: fprintf(listing,"=\n"); break;
case LT: fprintf(listing,"<\n"); break;
case LET: fprintf(listing,"<=\n"); break;
case GT: fprintf(listing,">\n"); break;
case GET: fprintf(listing,">=\n"); break;
case EQ: fprintf(listing,"==\n"); break;
case NEQ: fprintf(listing,"!=\n"); break;
case LPAREN: fprintf(listing,"(\n"); break;
case RPAREN: fprintf(listing,")\n"); break;
case LBRACKET: fprintf(listing,"[\n"); break;
case RBRACKET: fprintf(listing,"]\n"); break;
case LBRACE: fprintf(listing,"{\n"); break;
case RBRACE: fprintf(listing,"}\n"); break;
case SEMI: 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 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;
}

/* 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," ");
}

/* 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 IfK:
fprintf(listing,"If\n");
break;
case RepeatK:
fprintf(listing,"Repeat\n");
break;
case AssignK:
fprintf(listing,"Assign to: %s\n",tree->attr.name);
break;
case ReadK:
fprintf(listing,"Read: %s\n",tree->attr.name);
break;
case WriteK:
fprintf(listing,"Write\n");
break;
default:
fprintf(listing,"Unknown ExpNode kind\n");
break;
}
}
else if (tree->nodekind==ExpK)
{ switch (tree->kind.exp) {
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,"Id: %s\n",tree->attr.name);
break;
default:
fprintf(listing,"Unknown ExpNode kind\n");
break;
}
}
else fprintf(listing,"Unknown node kind\n");
for (i=0;i<MAXCHILDREN;i++)
printTree(tree->child[i]);
tree = tree->sibling;
}
UNINDENT;
}
72 util.h
@@ -1,36 +1,36 @@
/****************************************************/
/* File: util.h */
/* Utility functions for the TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/

#ifndef _UTIL_H_
#define _UTIL_H_

/* Procedure printToken prints a token
* and its lexeme to the listing file
*/
void printToken( TokenType, const char* );

/* Function newStmtNode creates a new statement
* node for syntax tree construction
*/
TreeNode * newStmtNode(StmtKind);

/* Function newExpNode creates a new expression
* node for syntax tree construction
*/
TreeNode * newExpNode(ExpKind);

/* Function copyString allocates and makes a new
* copy of an existing string
*/
char * copyString( char * );

/* procedure printTree prints a syntax tree to the
* listing file using indentation to indicate subtrees
*/
void printTree( TreeNode * );

#endif
/****************************************************/
/* File: util.h */
/* Utility functions for the TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/

#ifndef _UTIL_H_
#define _UTIL_H_

/* Procedure printToken prints a token
* and its lexeme to the listing file
*/
void printToken( TokenType, const char* );

/* Function newStmtNode creates a new statement
* node for syntax tree construction
*/
TreeNode * newStmtNode(StmtKind);

/* Function newExpNode creates a new expression
* node for syntax tree construction
*/
TreeNode * newExpNode(ExpKind);

/* Function copyString allocates and makes a new
* copy of an existing string
*/
char * copyString( char * );

/* procedure printTree prints a syntax tree to the
* listing file using indentation to indicate subtrees
*/
void printTree( TreeNode * );

#endif