提交 1470f922 创建 作者: 赵鹏翀's avatar 赵鹏翀

init template

上级
/Debug
/Release
<?xml version="1.0" encoding="gb2312"?>
<OSLProject Version="1.00" Name="TINY">
<Configurations>
<Configuration Name="Debug" CommandArgument="sample.txt">
<Tool Name="PreBuildEventTool"/>
<Tool Name="CustomBuildTool" CommandLine="" Outputs="" AdditionalDependencies=""/>
<Tool Name="GCCCompilerTool" PreprocessorDefinitions="_DEBUG" GenerateDebugInformation="-1" AdditionalOptions="-fno-builtin"/>
<Tool Name="PreLinkEventTool"/>
<Tool Name="GCCLinkerTool" OutputFile="$(ProjectName).exe"/>
<Tool Name="PostBuildEventTool"/>
</Configuration>
<Configuration Name="Release" CommandArgument="sample.txt">
<Tool Name="PreBuildEventTool"/>
<Tool Name="CustomBuildTool" CommandLine="" Outputs="" AdditionalDependencies=""/>
<Tool Name="GCCCompilerTool" PreprocessorDefinitions="NDEBUG" AdditionalOptions="-fno-builtin"/>
<Tool Name="PreLinkEventTool"/>
<Tool Name="GCCLinkerTool" OutputFile="$(ProjectName).exe"/>
<Tool Name="PostBuildEventTool"/>
</Configuration>
</Configurations>
<Files>
<Filter Name="TINY">
<File RelativePath=".\sample.tm.txt">
</File>
<File RelativePath=".\sample.txt">
<FileConfiguration Name="Debug">
<Tool Name="CustomBuildTool" CommandLine="" Outputs="" AdditionalDependencies=""/>
</FileConfiguration>
</File>
</Filter>
<Filter Name="ͷļ" Filter="h;hpp;hxx">
<File RelativePath=".\analyze.h">
</File>
<File RelativePath=".\cgen.h">
</File>
<File RelativePath=".\code.h">
</File>
<File RelativePath=".\globals.h">
</File>
<File RelativePath=".\parse.h">
</File>
<File RelativePath=".\scan.h">
</File>
<File RelativePath=".\symtab.h">
</File>
<File RelativePath=".\util.h">
</File>
</Filter>
<Filter Name="Դļ" Filter="cpp;c;cc;cxx">
<File RelativePath=".\analyze.c">
</File>
<File RelativePath=".\cgen.c">
</File>
<File RelativePath=".\code.c">
</File>
<File RelativePath=".\main.c">
</File>
<File RelativePath=".\parse.c">
</File>
<File RelativePath=".\scan.c">
</File>
<File RelativePath=".\symtab.c">
</File>
<File RelativePath=".\util.c">
</File>
</Filter>
</Files>
</OSLProject>
添加文件
/****************************************************/
/* 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);
}
/****************************************************/
/* File: analyze.h */
/* Semantic analyzer interface for TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#ifndef _ANALYZE_H_
#define _ANALYZE_H_
/* Function buildSymtab constructs the symbol
* table by preorder traversal of the syntax tree
*/
void buildSymtab(TreeNode *);
/* Procedure typeCheck performs type checking
* by a postorder syntax tree traversal
*/
void typeCheck(TreeNode *);
#endif
/****************************************************/
/* File: cgen.c */
/* The code generator implementation */
/* for the TINY compiler */
/* (generates code for the TM machine) */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#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
stored, and incremeted when loaded again
*/
static int tmpOffset = 0;
/* prototype for internal recursive code generator */
static void cGen (TreeNode * tree);
/* Procedure genStmt generates code at a statement node */
static void genStmt( TreeNode * tree)
{ TreeNode * p1, * p2, * p3;
int savedLoc1,savedLoc2,currentLoc;
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);
savedLoc1 = emitSkip(1) ;
emitComment("if: jump to else belongs here");
/* recurse on then part */
cGen(p2);
savedLoc2 = emitSkip(1) ;
emitComment("if: jump to end belongs here");
currentLoc = emitSkip(0) ;
emitBackup(savedLoc1) ;
emitRM_Abs("JEQ",ac,currentLoc,"if: jmp to else");
emitRestore() ;
/* recurse on else part */
cGen(p3);
currentLoc = emitSkip(0) ;
emitBackup(savedLoc2) ;
emitRM_Abs("LDA",pc,currentLoc,"jmp to end") ;
emitRestore() ;
if (TraceCode) emitComment("<- if") ;
break; /* if_k */
case RepeatK:
if (TraceCode) emitComment("-> repeat") ;
p1 = tree->child[0] ;
p2 = tree->child[1] ;
savedLoc1 = 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,savedLoc1,"repeat: jmp back to body");
if (TraceCode) emitComment("<- repeat") ;
break; /* repeat */
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; /* assign_k */
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;
}
} /* genStmt */
/* Procedure genExp generates 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; /* ConstK */
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; /* IdK */
case OpK :
if (TraceCode) emitComment("-> Op") ;
p1 = tree->child[0];
p2 = tree->child[1];
/* gen code for ac = left arg */
cGen(p1);
/* gen code to 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 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 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;
} /* case op */
if (TraceCode) emitComment("<- Op") ;
break; /* OpK */
default:
break;
}
} /* genExp */
/* Procedure cGen recursively generates 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 generates code to a code
* file by traversal of the syntax tree. The
* second parameter (codefile) is the file name
* of the code file, and is used to 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 prelude:");
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,"");
}
/****************************************************/
/* File: cgen.h */
/* The code generator interface to the TINY compiler*/
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#ifndef _CGEN_H_
#define _CGEN_H_
/* Procedure codeGen generates code to a code
* file by traversal of the syntax tree. The
* second parameter (codefile) is the file name
* of the code file, and is used to print the
* file name as a comment in the code file
*/
void codeGen(TreeNode * syntaxTree, char * codefile);
#endif
/****************************************************/
/* File: code.c */
/* TM Code emitting utilities */
/* implementation for the TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#include "globals.h"
#include "code.h"
/* TM location number for current instruction emission */
static int emitLoc = 0 ;
/* Highest TM location emitted so far
For use in conjunction with emitSkip,
emitBackup, and emitRestore */
static int highEmitLoc = 0;
/* Procedure emitComment prints a comment line
* with comment c in the code file
*/
void emitComment( char * c )
{ if (TraceCode) fprintf(code,"* %s\n",c);}
/* Procedure emitRO emits a register-only
* TM instruction
* op = the opcode
* r = target register
* s = 1st source register
* t = 2nd source register
* c = a comment to be printed if TraceCode is TRUE
*/
void emitRO( char *op, int r, int s, int t, char *c)
{ fprintf(code,"%3d: %5s %d,%d,%d ",emitLoc++,op,r,s,t);
if (TraceCode) fprintf(code,"\t%s",c) ;
fprintf(code,"\n") ;
if (highEmitLoc < emitLoc) highEmitLoc = emitLoc ;
} /* emitRO */
/* Procedure emitRM emits a register-to-memory
* TM instruction
* op = the opcode
* r = target register
* d = the offset
* s = the base register
* c = a comment to be printed if TraceCode is TRUE
*/
void emitRM( char * op, int r, int d, int s, char *c)
{ fprintf(code,"%3d: %5s %d,%d(%d) ",emitLoc++,op,r,d,s);
if (TraceCode) fprintf(code,"\t%s",c) ;
fprintf(code,"\n") ;
if (highEmitLoc < emitLoc) highEmitLoc = emitLoc ;
} /* emitRM */
/* Function emitSkip skips "howMany" code
* locations for later backpatch. It also
* returns the current code position
*/
int emitSkip( int howMany)
{ int i = emitLoc;
emitLoc += howMany ;
if (highEmitLoc < emitLoc) highEmitLoc = emitLoc ;
return i;
} /* emitSkip */
/* Procedure emitBackup backs up to
* loc = a previously skipped location
*/
void emitBackup( int loc)
{ if (loc > highEmitLoc) emitComment("BUG in emitBackup");
emitLoc = loc ;
} /* emitBackup */
/* Procedure emitRestore restores the current
* code position to the highest previously
* unemitted position
*/
void emitRestore(void)
{ emitLoc = highEmitLoc;}
/* Procedure emitRM_Abs converts an absolute reference
* to a pc-relative reference when emitting a
* register-to-memory TM instruction
* op = the opcode
* r = target register
* a = the absolute location in memory
* c = a comment to be printed if TraceCode is TRUE
*/
void emitRM_Abs( char *op, int r, int a, char * c)
{
fprintf(code,"%3d: %5s %d,%d(%d) ",
emitLoc,op,r,a-(emitLoc+1),pc);
++emitLoc ;
if (TraceCode) fprintf(code,"\t%s",c) ;
fprintf(code,"\n") ;
if (highEmitLoc < emitLoc) highEmitLoc = emitLoc ;
} /* emitRM_Abs */
/****************************************************/
/* File: code.h */
/* Code emitting utilities for the TINY compiler */
/* and interface to the TM machine */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#ifndef _CODE_H_
#define _CODE_H_
/* pc = program counter */
#define pc 7
/* mp = "memory pointer" points
* to top of memory (for temp storage)
*/
#define mp 6
/* gp = "global pointer" points
* to bottom of memory for (global)
* variable storage
*/
#define gp 5
/* accumulator */
#define ac 0
/* 2nd accumulator */
#define ac1 1
/* code emitting utilities */
/* Procedure emitComment prints a comment line
* with comment c in the code file
*/
void emitComment( char * c );
/* Procedure emitRO emits a register-only
* TM instruction
* op = the opcode
* r = target register
* s = 1st source register
* t = 2nd source register
* c = a comment to be printed if TraceCode is TRUE
*/
void emitRO( char *op, int r, int s, int t, char *c);
/* Procedure emitRM emits a register-to-memory
* TM instruction
* op = the opcode
* r = target register
* d = the offset
* s = the base register
* c = a comment to be printed if TraceCode is TRUE
*/
void emitRM( char * op, int r, int d, int s, char *c);
/* Function emitSkip skips "howMany" code
* locations for later backpatch. It also
* returns the current code position
*/
int emitSkip( int howMany);
/* Procedure emitBackup backs up to
* loc = a previously skipped location
*/
void emitBackup( int loc);
/* Procedure emitRestore restores the current
* code position to the highest previously
* unemitted position
*/
void emitRestore(void);
/* Procedure emitRM_Abs converts an absolute reference
* to a pc-relative reference when emitting a
* register-to-memory TM instruction
* op = the opcode
* r = target register
* a = the absolute location in memory
* c = a comment to be printed if TraceCode is TRUE
*/
void emitRM_Abs( char *op, int r, int a, char * c);
#endif
/****************************************************/
/* File: globals.h */
/* Global types and vars for TINY compiler */
/* must come before other include files */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#ifndef _GLOBALS_H_
#define _GLOBALS_H_
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
/* MAXRESERVED = the number of reserved words */
#define MAXRESERVED 8
typedef enum
/* book-keeping tokens */
{ENDFILE,ERROR,
/* reserved words */
IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,
/* multicharacter tokens */
ID,NUM,
/* special symbols */
ASSIGN,EQ,LT,PLUS,MINUS,TIMES,OVER,LPAREN,RPAREN,SEMI
} TokenType;
extern FILE* source; /* source code text file */
extern FILE* listing; /* listing output text file */
extern FILE* code; /* code text file for TM simulator */
extern int lineno; /* source line number for listing */
/**************************************************/
/*********** Syntax tree for parsing ************/
/**************************************************/
typedef enum {StmtK,ExpK} NodeKind;
typedef enum {IfK,RepeatK,AssignK,ReadK,WriteK} StmtKind;
typedef enum {OpK,ConstK,IdK} ExpKind;
/* ExpType is used for type checking */
typedef enum {Void,Integer,Boolean} ExpType;
#define MAXCHILDREN 3
typedef struct treeNode
{ struct treeNode * child[MAXCHILDREN];
struct treeNode * sibling;
int lineno;
NodeKind nodekind;
union { StmtKind stmt; ExpKind exp;} kind;
union { TokenType op;
int val;
char * name; } attr;
ExpType type; /* for type checking of exps */
} TreeNode;
/**************************************************/
/*********** Flags for tracing ************/
/**************************************************/
/* EchoSource = TRUE causes the source program to
* be echoed to the listing file with line numbers
* during parsing
*/
extern int EchoSource;
/* TraceScan = TRUE causes token information to be
* printed to the listing file as each token is
* recognized by the scanner
*/
extern int TraceScan;
/* TraceParse = TRUE causes the syntax tree to be
* printed to the listing file in linearized form
* (using indents for children)
*/
extern int TraceParse;
/* TraceAnalyze = TRUE causes symbol table inserts
* and lookups to be reported to the listing file
*/
extern int TraceAnalyze;
/* TraceCode = TRUE causes comments to be written
* to the TM code file as code is generated
*/
extern int TraceCode;
/* Error = TRUE prevents further passes if an error occurs */
extern int Error;
#endif
/****************************************************/
/* 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 FALSE
/* set NO_ANALYZE to TRUE to get a parser-only compiler */
#define NO_ANALYZE FALSE
/* set NO_CODE to TRUE to get a compiler that does not
* generate code
*/
#define NO_CODE FALSE
#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 = FALSE;
int TraceScan = FALSE;
int TraceParse = FALSE;
int TraceAnalyze = FALSE;
int TraceCode = FALSE;
int Error = FALSE;
char pgm[256]; /* source code file name */
main( int argc, char * argv[] )
{
TreeNode * syntaxTree;
if (argc != 2)
{
fprintf(stderr,"usage: %s <filename>\n",argv[0]);
exit(1);
}
strcpy(pgm, argv[1]) ;
if (strchr (pgm, '.') == NULL)
strcat(pgm,".tny");
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.txt");
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: parse.c */
/* The parser implementation for the TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#include "globals.h"
#include "util.h"
#include "scan.h"
#include "parse.h"
static TokenType token; /* holds current token */
/* function prototypes for recursive calls */
static TreeNode * stmt_sequence(void);
static TreeNode * statement(void);
static TreeNode * if_stmt(void);
static TreeNode * repeat_stmt(void);
static TreeNode * assign_stmt(void);
static TreeNode * read_stmt(void);
static TreeNode * write_stmt(void);
static TreeNode * exp(void);
static TreeNode * simple_exp(void);
static TreeNode * term(void);
static TreeNode * factor(void);
extern char pgm[256];
// G:\Documents and Settings\xjx\My Documents\CP Lab\Projects\trter\main.c:40: error: syntax error before "int"
// Syntax error at line 11: unexpected token -> reserved word: until
static void syntaxError(char * message)
{
fprintf(listing,"\n%s:%d: error: %s",pgm, lineno, message);
Error = TRUE;
}
static void match(TokenType expected)
{ if (token == expected) token = getToken();
else {
syntaxError("unexpected token -> ");
printToken(token,tokenString);
fprintf(listing," ");
}
}
TreeNode * stmt_sequence(void)
{ TreeNode * t = statement();
TreeNode * p = t;
while ((token!=ENDFILE) && (token!=END) &&
(token!=ELSE) && (token!=UNTIL))
{ TreeNode * q;
match(SEMI);
q = statement();
if (q!=NULL) {
if (t==NULL) t = p = q;
else /* now p cannot be NULL either */
{ p->sibling = q;
p = q;
}
}
}
return t;
}
TreeNode * statement(void)
{ TreeNode * t = NULL;
switch (token) {
case IF : t = if_stmt(); break;
case REPEAT : t = repeat_stmt(); break;
case ID : t = assign_stmt(); break;
case READ : t = read_stmt(); break;
case WRITE : t = write_stmt(); break;
default : syntaxError("unexpected token -> ");
printToken(token,tokenString);
token = getToken();
break;
} /* end case */
return t;
}
TreeNode * if_stmt(void)
{ TreeNode * t = newStmtNode(IfK);
match(IF);
if (t!=NULL) t->child[0] = exp();
match(THEN);
if (t!=NULL) t->child[1] = stmt_sequence();
if (token==ELSE) {
match(ELSE);
if (t!=NULL) t->child[2] = stmt_sequence();
}
match(END);
return t;
}
TreeNode * repeat_stmt(void)
{ TreeNode * t = newStmtNode(RepeatK);
match(REPEAT);
if (t!=NULL) t->child[0] = stmt_sequence();
match(UNTIL);
if (t!=NULL) t->child[1] = exp();
return t;
}
TreeNode * assign_stmt(void)
{ TreeNode * t = newStmtNode(AssignK);
if ((t!=NULL) && (token==ID))
t->attr.name = copyString(tokenString);
match(ID);
match(ASSIGN);
if (t!=NULL) t->child[0] = exp();
return t;
}
TreeNode * read_stmt(void)
{ TreeNode * t = newStmtNode(ReadK);
match(READ);
if ((t!=NULL) && (token==ID))
t->attr.name = copyString(tokenString);
match(ID);
return t;
}
TreeNode * write_stmt(void)
{ TreeNode * t = newStmtNode(WriteK);
match(WRITE);
if (t!=NULL) t->child[0] = exp();
return t;
}
static TreeNode * exp(void)
{ TreeNode * t = simple_exp();
if ((token==LT)||(token==EQ)) {
TreeNode * p = newExpNode(OpK);
if (p!=NULL) {
p->child[0] = t;
p->attr.op = token;
t = p;
}
match(token);
if (t!=NULL)
t->child[1] = simple_exp();
}
return t;
}
TreeNode * simple_exp(void)
{ TreeNode * t = term();
while ((token==PLUS)||(token==MINUS))
{ TreeNode * p = newExpNode(OpK);
if (p!=NULL) {
p->child[0] = t;
p->attr.op = token;
t = p;
match(token);
t->child[1] = term();
}
}
return t;
}
TreeNode * term(void)
{ TreeNode * t = factor();
while ((token==TIMES)||(token==OVER))
{ TreeNode * p = newExpNode(OpK);
if (p!=NULL) {
p->child[0] = t;
p->attr.op = token;
t = p;
match(token);
p->child[1] = factor();
}
}
return t;
}
TreeNode * factor(void)
{ TreeNode * t = NULL;
switch (token) {
case NUM :
t = newExpNode(ConstK);
if ((t!=NULL) && (token==NUM))
t->attr.val = atoi(tokenString);
match(NUM);
break;
case ID :
t = newExpNode(IdK);
if ((t!=NULL) && (token==ID))
t->attr.name = copyString(tokenString);
match(ID);
break;
case LPAREN :
match(LPAREN);
t = exp();
match(RPAREN);
break;
default:
syntaxError("unexpected token -> ");
printToken(token,tokenString);
token = getToken();
break;
}
return t;
}
/****************************************/
/* the primary function of the parser */
/****************************************/
/* Function parse returns the newly
* constructed syntax tree
*/
TreeNode * parse(void)
{ TreeNode * t;
token = getToken();
t = stmt_sequence();
if (token!=ENDFILE)
syntaxError("Code ends before file\n");
return t;
}
/****************************************************/
/* File: parse.h */
/* The parser interface for the TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#ifndef _PARSE_H_
#define _PARSE_H_
/* Function parse returns the newly
* constructed syntax tree
*/
TreeNode * parse(void);
#endif
{ Sample program
int TINY language -
computes factorial
}
read x; { input an integer }
if 0 < x then { don't compute if x <= 0 }
fact := 1;
repeat
fact := fact * x;
x := x - 1
until
x = 0;
write fact { output factorial of x }
end
/****************************************************/
/* File: scan.c */
/* The scanner implementation for the TINY compiler */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#include "globals.h"
#include "util.h"
#include "scan.h"
/* states in scanner DFA */
typedef enum
{ START,INASSIGN,INCOMMENT,INNUM,INID,DONE }
StateType;
/* lexeme of identifier or reserved word */
char tokenString[MAXTOKENLEN+1];
/* BUFLEN = length of the input buffer for
source code lines */
#define BUFLEN 256
static char lineBuf[BUFLEN]; /* holds the current line */
static int linepos = 0; /* current position in LineBuf */
static int bufsize = 0; /* current size of buffer string */
static int EOF_flag = FALSE; /* corrects ungetNextChar behavior on EOF */
/* getNextChar fetches the next non-blank character
from lineBuf, reading in a new line if lineBuf is
exhausted */
static int getNextChar(void)
{ if (!(linepos < bufsize))
{ lineno++;
if (fgets(lineBuf,BUFLEN-1,source))
{ if (EchoSource) fprintf(listing,"%4d: %s",lineno,lineBuf);
bufsize = strlen(lineBuf);
linepos = 0;
return lineBuf[linepos++];
}
else
{ EOF_flag = TRUE;
return EOF;
}
}
else return lineBuf[linepos++];
}
/* ungetNextChar backtracks one character
in lineBuf */
static void ungetNextChar(void)
{ if (!EOF_flag) linepos-- ;}
/* lookup table of reserved words */
static struct
{ char* str;
TokenType tok;
} reservedWords[MAXRESERVED]
= {{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},
{"repeat",REPEAT},{"until",UNTIL},{"read",READ},
{"write",WRITE}};
/* lookup an identifier to see if it is a reserved word */
/* uses linear search */
static TokenType reservedLookup (char * s)
{ int i;
for (i=0;i<MAXRESERVED;i++)
if (!strcmp(s,reservedWords[i].str))
return reservedWords[i].tok;
return ID;
}
/****************************************/
/* the primary function of the scanner */
/****************************************/
/* function getToken returns the
* next token in source file
*/
TokenType getToken(void)
{ /* index for storing into tokenString */
int tokenStringIndex = 0;
/* holds current token to be returned */
TokenType currentToken;
/* current state - always begins at START */
StateType state = START;
/* flag to indicate save to tokenString */
int save;
while (state != DONE)
{ int c = getNextChar();
save = TRUE;
switch (state)
{ case START:
if (isdigit(c))
state = INNUM;
else if (isalpha(c))
state = INID;
else if (c == ':')
state = INASSIGN;
else if ((c == ' ') || (c == '\t') || (c == '\n'))
save = FALSE;
else if (c == '{')
{ save = FALSE;
state = INCOMMENT;
}
else
{ state = DONE;
switch (c)
{ case EOF:
save = FALSE;
currentToken = ENDFILE;
break;
case '=':
currentToken = EQ;
break;
case '<':
currentToken = LT;
break;
case '+':
currentToken = PLUS;
break;
case '-':
currentToken = MINUS;
break;
case '*':
currentToken = TIMES;
break;
case '/':
currentToken = OVER;
break;
case '(':
currentToken = LPAREN;
break;
case ')':
currentToken = RPAREN;
break;
case ';':
currentToken = SEMI;
break;
default:
currentToken = ERROR;
break;
}
}
break;
case INCOMMENT:
save = FALSE;
if (c == EOF)
{ state = DONE;
currentToken = ENDFILE;
}
else if (c == '}') state = START;
break;
case INASSIGN:
state = DONE;
if (c == '=')
currentToken = ASSIGN;
else
{ /* backup in the input */
ungetNextChar();
save = FALSE;
currentToken = ERROR;
}
break;
case INNUM:
if (!isdigit(c))
{ /* backup in the input */
ungetNextChar();
save = FALSE;
state = DONE;
currentToken = NUM;
}
break;
case INID:
if (!isalpha(c))
{ /* backup in the input */
ungetNextChar();
save = FALSE;
state = DONE;
currentToken = ID;
}
break;
case DONE:
default: /* should never happen */
fprintf(listing,"Scanner Bug: state= %d\n",state);
state = DONE;
currentToken = ERROR;
break;
}
if ((save) && (tokenStringIndex <= MAXTOKENLEN))
tokenString[tokenStringIndex++] = (char) c;
if (state == DONE)
{ tokenString[tokenStringIndex] = '\0';
if (currentToken == ID)
currentToken = reservedLookup(tokenString);
}
}
if (TraceScan) {
fprintf(listing,"\t%d: ",lineno);
printToken(currentToken,tokenString);
}
return currentToken;
} /* end getToken */
/****************************************************/
/* 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: symtab.c */
/* Symbol table implementation for the TINY compiler*/
/* (allows only one symbol table) */
/* Symbol table is implemented as a chained */
/* hash table */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "symtab.h"
/* SIZE is the size of the hash table */
#define SIZE 211
/* SHIFT is the power of two used as multiplier
in hash function */
#define SHIFT 4
/* the hash function */
static int hash ( char * key )
{ int temp = 0;
int i = 0;
while (key[i] != '\0')
{ temp = ((temp << SHIFT) + key[i]) % SIZE;
++i;
}
return temp;
}
/* the list of line numbers of the source
* code in which a variable is referenced
*/
typedef struct LineListRec
{ int lineno;
struct LineListRec * next;
} * LineList;
/* The record in the bucket lists for
* each variable, including name,
* assigned memory location, and
* the list of line numbers in which
* it appears in the source code
*/
typedef struct BucketListRec
{ char * name;
LineList lines;
int memloc ; /* memory location for variable */
struct BucketListRec * next;
} * BucketList;
/* the hash table */
static BucketList hashTable[SIZE];
/* Procedure st_insert inserts line numbers and
* memory locations into the symbol table
* loc = memory location is inserted only the
* first time, otherwise ignored
*/
void st_insert( char * name, int lineno, int loc )
{ int h = hash(name);
BucketList l = hashTable[h];
while ((l != NULL) && (strcmp(name,l->name) != 0))
l = l->next;
if (l == NULL) /* variable not yet in table */
{ l = (BucketList) malloc(sizeof(struct BucketListRec));
l->name = name;
l->lines = (LineList) malloc(sizeof(struct LineListRec));
l->lines->lineno = lineno;
l->memloc = loc;
l->lines->next = NULL;
l->next = hashTable[h];
hashTable[h] = l; }
else /* found in table, so just add line number */
{ LineList t = l->lines;
while (t->next != NULL) t = t->next;
t->next = (LineList) malloc(sizeof(struct LineListRec));
t->next->lineno = lineno;
t->next->next = NULL;
}
} /* st_insert */
/* Function st_lookup returns the memory
* location of a variable or -1 if not found
*/
int st_lookup ( char * name )
{ int h = hash(name);
BucketList l = hashTable[h];
while ((l != NULL) && (strcmp(name,l->name) != 0))
l = l->next;
if (l == NULL) return -1;
else return l->memloc;
}
/* Procedure printSymTab prints a formatted
* listing of the symbol table contents
* to the listing file
*/
void printSymTab(FILE * listing)
{ int i;
fprintf(listing,"Variable Name Location Line Numbers\n");
fprintf(listing,"------------- -------- ------------\n");
for (i=0;i<SIZE;++i)
{ if (hashTable[i] != NULL)
{ BucketList l = hashTable[i];
while (l != NULL)
{ LineList t = l->lines;
fprintf(listing,"%-14s ",l->name);
fprintf(listing,"%-8d ",l->memloc);
while (t != NULL)
{ fprintf(listing,"%4d ",t->lineno);
t = t->next;
}
fprintf(listing,"\n");
l = l->next;
}
}
}
} /* printSymTab */
/****************************************************/
/* File: symtab.h */
/* Symbol table interface for the TINY compiler */
/* (allows only one symbol table) */
/* Compiler Construction: Principles and Practice */
/* Kenneth C. Louden */
/****************************************************/
#ifndef _SYMTAB_H_
#define _SYMTAB_H_
/* Procedure st_insert inserts line numbers and
* memory locations into the symbol table
* loc = memory location is inserted only the
* first time, otherwise ignored
*/
void st_insert( char * name, int lineno, int loc );
/* Function st_lookup returns the memory
* location of a variable or -1 if not found
*/
int st_lookup ( char * name );
/* Procedure printSymTab prints a formatted
* listing of the symbol table contents
* to the listing file
*/
void printSymTab(FILE * listing);
#endif
/****************************************************/
/* 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 THEN:
case ELSE:
case END:
case REPEAT:
case UNTIL:
case READ:
case WRITE:
fprintf(listing,
"reserved word: %s\n",tokenString);
break;
case ASSIGN: fprintf(listing,":=\n"); break;
case LT: fprintf(listing,"<\n"); break;
case EQ: fprintf(listing,"=\n"); break;
case LPAREN: fprintf(listing,"(\n"); break;
case RPAREN: 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 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 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.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
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论