Commit c30bbd12c19674ba2f4945fe4fec04457ef33406
0 parents
Exists in
master
well
Showing 37 changed files with 3036 additions and 0 deletions Side-by-side Diff
- Makefile
- Project_Description.txt
- README.md
- ast.cc
- ast.h
- ast_decl.cc
- ast_decl.h
- ast_expr.cc
- ast_expr.h
- ast_stmt.cc
- ast_stmt.h
- ast_type.cc
- ast_type.h
- errors.cc
- errors.h
- gli
- irgen.cc
- irgen.h
- list.h
- location.h
- main.cc
- parser.h
- parser.y
- public_samples/foo.dat
- public_samples/foo.glsl
- public_samples/foo.out
- public_samples/vec2_test.dat
- public_samples/vec2_test.glsl
- public_samples/vec2_test.out
- runall.sh
- scanner.h
- scanner.l
- submission.sh
- symtable.cc
- symtable.h
- utility.cc
- utility.h
Makefile
View file @
c30bbd1
... | ... | @@ -0,0 +1,87 @@ |
1 | +## | |
2 | +## Simple makefile for CS131 programming projects | |
3 | +## | |
4 | + | |
5 | + | |
6 | +.PHONY: clean strip | |
7 | + | |
8 | +# Set the default target. When you make with no arguments, | |
9 | +# this will be the target built. | |
10 | +COMPILER = glc | |
11 | +PRODUCTS = $(COMPILER) | |
12 | +default: $(PRODUCTS) | |
13 | + | |
14 | +# Set up the list of source and object files | |
15 | +SRCS = ast.cc ast_decl.cc ast_expr.cc ast_stmt.cc ast_type.cc errors.cc utility.cc main.cc symtable.cc irgen.cc | |
16 | + | |
17 | +# OBJS can deal with either .cc or .c files listed in SRCS | |
18 | +OBJS = y.tab.o lex.yy.o $(patsubst %.cc, %.o, $(filter %.cc,$(SRCS))) $(patsubst %.c, %.o, $(filter %.c, $(SRCS))) | |
19 | + | |
20 | +JUNK = *.o lex.yy.c dpp.yy.c y.tab.c y.tab.h *.core core *~ | |
21 | + | |
22 | +# Define the tools we are going to use | |
23 | +CC= g++ | |
24 | +LD = g++ | |
25 | +LEX = flex | |
26 | +YACC = bison | |
27 | + | |
28 | +# Set up the necessary flags for the tools | |
29 | + | |
30 | +# We want debugging and most warnings, but lex/yacc generate some | |
31 | +# static symbols we don't use, so turn off unused warnings to avoid clutter | |
32 | +# Also STL has some signed/unsigned comparisons we want to suppress | |
33 | +CFLAGS = -g -Wall -Wno-unused -Wno-sign-compare `llvm-config --cxxflags` | |
34 | + | |
35 | +# The -d flag tells lex to set up for debugging. Can turn on/off by | |
36 | +# setting value of global yy_flex_debug inside the scanner itself | |
37 | +LEXFLAGS = -d | |
38 | + | |
39 | +# The -d flag tells yacc to generate header with token types | |
40 | +# The -v flag writes out a verbose description of the states and conflicts | |
41 | +# The -t flag turns on debugging capability | |
42 | +# The -y flag means imitate yacc's output file naming conventions | |
43 | +YACCFLAGS = -dvty | |
44 | +# YACCFLAGS = -dvty --report=all --report-file=y.debug | |
45 | + | |
46 | +# Link with standard C library, math library, and lex library | |
47 | +LIBS = -lc -lm -ll `llvm-config --ldflags --libs` | |
48 | + | |
49 | +# Rules for various parts of the target | |
50 | + | |
51 | +.yy.o: $*.yy.c | |
52 | + $(CC) $(CFLAGS) -c -o $@ $*.cc | |
53 | + | |
54 | +lex.yy.c: scanner.l parser.y y.tab.h | |
55 | + $(LEX) $(LEXFLAGS) scanner.l | |
56 | + | |
57 | +y.tab.o: y.tab.c | |
58 | + $(CC) $(CFLAGS) -c -o y.tab.o y.tab.c | |
59 | + | |
60 | +y.tab.h y.tab.c: parser.y | |
61 | + $(YACC) $(YACCFLAGS) parser.y | |
62 | +.cc.o: $*.cc | |
63 | + $(CC) $(CFLAGS) -c -o $@ $*.cc | |
64 | + | |
65 | +# rules to build compiler (dcc) | |
66 | + | |
67 | +$(COMPILER) : $(OBJS) | |
68 | + $(LD) -o $@ $(OBJS) $(LIBS) | |
69 | + | |
70 | + | |
71 | +# This target is to build small for testing (no debugging info), removes | |
72 | +# all intermediate products, too | |
73 | +strip : $(PRODUCTS) | |
74 | + strip $(PRODUCTS) | |
75 | + rm -rf $(JUNK) | |
76 | + | |
77 | + | |
78 | +# make depend will set up the header file dependencies for the | |
79 | +# assignment. You should make depend whenever you add a new header | |
80 | +# file to the project or move the project between machines | |
81 | +# | |
82 | +depend: | |
83 | + makedepend -- $(CFLAGS) -- $(SRCS) | |
84 | + | |
85 | +clean: | |
86 | + rm -f $(JUNK) y.output $(PRODUCTS) | |
87 | + |
README.md
View file @
c30bbd1
... | ... | @@ -0,0 +1,16 @@ |
1 | +# CSE131 | |
2 | + | |
3 | +Describe briefly how you approached the project in Project_Description.txt | |
4 | + | |
5 | +Fill in the name email and pid in the script submission.sh | |
6 | +Execute the script like | |
7 | + | |
8 | +$ ./submission.sh | |
9 | + | |
10 | +if it fails to execute then try changing the permissions like | |
11 | +$ chmod +x submission.sh | |
12 | + | |
13 | +if it fails for other reasons, then fix the name,email, pid etc whatever the error message says. | |
14 | + | |
15 | + | |
16 | +After it executes, you would get a zip file which you need to submit on the link given in piazza submission guildelines. |
ast.cc
View file @
c30bbd1
... | ... | @@ -0,0 +1,48 @@ |
1 | +/* File: ast.cc | |
2 | + * ------------ | |
3 | + */ | |
4 | + | |
5 | +#include "ast.h" | |
6 | +#include "ast_type.h" | |
7 | +#include "ast_decl.h" | |
8 | +#include "symtable.h" | |
9 | +#include <string.h> // strdup | |
10 | +#include <stdio.h> // printf | |
11 | + | |
12 | +Node::Node(yyltype loc) { | |
13 | + location = new yyltype(loc); | |
14 | + parent = NULL; | |
15 | +} | |
16 | + | |
17 | +Node::Node() { | |
18 | + location = NULL; | |
19 | + parent = NULL; | |
20 | +} | |
21 | + | |
22 | +/* The Print method is used to print the parse tree nodes. | |
23 | + * If this node has a location (most nodes do, but some do not), it | |
24 | + * will first print the line number to help you match the parse tree | |
25 | + * back to the source text. It then indents the proper number of levels | |
26 | + * and prints the "print name" of the node. It then will invoke the | |
27 | + * virtual function PrintChildren which is expected to print the | |
28 | + * internals of the node (itself & children) as appropriate. | |
29 | + */ | |
30 | +void Node::Print(int indentLevel, const char *label) { | |
31 | + const int numSpaces = 3; | |
32 | + printf("\n"); | |
33 | + if (GetLocation()) | |
34 | + printf("%*d", numSpaces, GetLocation()->first_line); | |
35 | + else | |
36 | + printf("%*s", numSpaces, ""); | |
37 | + printf("%*s%s%s: ", indentLevel*numSpaces, "", | |
38 | + label? label : "", GetPrintNameForNode()); | |
39 | + PrintChildren(indentLevel); | |
40 | +} | |
41 | + | |
42 | +Identifier::Identifier(yyltype loc, const char *n) : Node(loc) { | |
43 | + name = strdup(n); | |
44 | +} | |
45 | + | |
46 | +void Identifier::PrintChildren(int indentLevel) { | |
47 | + printf("%s", name); | |
48 | +} |
ast.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,103 @@ |
1 | +/** | |
2 | + * File: ast.h | |
3 | + * ----------- | |
4 | + * This file defines the abstract base class Node and the concrete | |
5 | + * Identifier and Error node subclasses that are used through the tree as | |
6 | + * leaf nodes. A parse tree is a hierarchical collection of ast nodes (or, | |
7 | + * more correctly, of instances of concrete subclassses such as VarDecl, | |
8 | + * ForStmt, and AssignExpr). | |
9 | + * | |
10 | + * Location: Each node maintains its lexical location (line and columns in | |
11 | + * file), that location can be NULL for those nodes that don't care/use | |
12 | + * locations. The location is typcially set by the node constructor. The | |
13 | + * location is used to provide the context when reporting semantic errors. | |
14 | + * | |
15 | + * Parent: Each node has a pointer to its parent. For a Program node, the | |
16 | + * parent is NULL, for all other nodes it is the pointer to the node one level | |
17 | + * up in the parse tree. The parent is not set in the constructor (during a | |
18 | + * bottom-up parse we don't know the parent at the time of construction) but | |
19 | + * instead we wait until assigning the children into the parent node and then | |
20 | + * set up links in both directions. The parent link is typically not used | |
21 | + * during parsing, but is more important in later phases. | |
22 | + * | |
23 | + * Printing: This functionaility is saved from pp2 of the node classes to | |
24 | + * print out the AST tree for debugging purpose. Each node class is | |
25 | + * responsible for printing itself/children by overriding the virtual | |
26 | + * PrintChildren() and GetPrintNameForNode() methods. All the classes we | |
27 | + * provide already implement these methods, so your job is to construct the | |
28 | + * nodes and wire them up during parsing. Once that's done, printing is a snap! | |
29 | + | |
30 | + * Semantic analysis: For pp3 you are adding "Check" behavior to the ast | |
31 | + * node classes. Your semantic analyzer should do an inorder walk on the | |
32 | + * parse tree, and when visiting each node, verify the particular | |
33 | + * semantic rules that apply to that construct. | |
34 | + | |
35 | + */ | |
36 | + | |
37 | +#ifndef _H_ast | |
38 | +#define _H_ast | |
39 | + | |
40 | +#include <stdlib.h> // for NULL | |
41 | +#include "location.h" | |
42 | +#include <iostream> | |
43 | + | |
44 | +using namespace std; | |
45 | + | |
46 | +class SymbolTable; | |
47 | +class MyStack; | |
48 | +class FnDecl; | |
49 | + | |
50 | +class Node { | |
51 | + protected: | |
52 | + yyltype *location; | |
53 | + Node *parent; | |
54 | + | |
55 | + public: | |
56 | + Node(yyltype loc); | |
57 | + Node(); | |
58 | + virtual ~Node() {} | |
59 | + | |
60 | + yyltype *GetLocation() { return location; } | |
61 | + void SetParent(Node *p) { parent = p; } | |
62 | + Node *GetParent() { return parent; } | |
63 | + | |
64 | + virtual const char *GetPrintNameForNode() = 0; | |
65 | + | |
66 | + // Print() is deliberately _not_ virtual | |
67 | + // subclasses should override PrintChildren() instead | |
68 | + void Print(int indentLevel, const char *label = NULL); | |
69 | + virtual void PrintChildren(int indentLevel) {} | |
70 | + | |
71 | + virtual void Emit() {} | |
72 | +}; | |
73 | + | |
74 | + | |
75 | +class Identifier : public Node | |
76 | +{ | |
77 | + protected: | |
78 | + char *name; | |
79 | + | |
80 | + public: | |
81 | + Identifier(yyltype loc, const char *name); | |
82 | + const char *GetPrintNameForNode() { return "Identifier"; } | |
83 | + char *GetName() const { return name; } | |
84 | + void PrintChildren(int indentLevel); | |
85 | + friend ostream& operator<<(ostream& out, Identifier *id) { return out << id->name; } | |
86 | +}; | |
87 | + | |
88 | + | |
89 | +// This node class is designed to represent a portion of the tree that | |
90 | +// encountered syntax errors during parsing. The partial completed tree | |
91 | +// is discarded along with the states being popped, and an instance of | |
92 | +// the Error class can stand in as the placeholder in the parse tree | |
93 | +// when your parser can continue after an error. | |
94 | +class Error : public Node | |
95 | +{ | |
96 | + public: | |
97 | + Error() : Node() {} | |
98 | + const char *GetPrintNameForNode() { return "Error"; } | |
99 | +}; | |
100 | + | |
101 | + | |
102 | + | |
103 | +#endif |
ast_decl.cc
View file @
c30bbd1
... | ... | @@ -0,0 +1,69 @@ |
1 | +/* File: ast_decl.cc | |
2 | + * ----------------- | |
3 | + * Implementation of Decl node classes. | |
4 | + */ | |
5 | +#include "ast_decl.h" | |
6 | +#include "ast_type.h" | |
7 | +#include "ast_stmt.h" | |
8 | +#include "symtable.h" | |
9 | + | |
10 | +Decl::Decl(Identifier *n) : Node(*n->GetLocation()) { | |
11 | + Assert(n != NULL); | |
12 | + (id=n)->SetParent(this); | |
13 | +} | |
14 | + | |
15 | +VarDecl::VarDecl(Identifier *n, Type *t, Expr *e) : Decl(n) { | |
16 | + Assert(n != NULL && t != NULL); | |
17 | + (type=t)->SetParent(this); | |
18 | + if (e) (assignTo=e)->SetParent(this); | |
19 | + typeq = NULL; | |
20 | +} | |
21 | + | |
22 | +VarDecl::VarDecl(Identifier *n, TypeQualifier *tq, Expr *e) : Decl(n) { | |
23 | + Assert(n != NULL && tq != NULL); | |
24 | + (typeq=tq)->SetParent(this); | |
25 | + if (e) (assignTo=e)->SetParent(this); | |
26 | + type = NULL; | |
27 | +} | |
28 | + | |
29 | +VarDecl::VarDecl(Identifier *n, Type *t, TypeQualifier *tq, Expr *e) : Decl(n) { | |
30 | + Assert(n != NULL && t != NULL && tq != NULL); | |
31 | + (type=t)->SetParent(this); | |
32 | + (typeq=tq)->SetParent(this); | |
33 | + if (e) (assignTo=e)->SetParent(this); | |
34 | +} | |
35 | + | |
36 | +void VarDecl::PrintChildren(int indentLevel) { | |
37 | + if (typeq) typeq->Print(indentLevel+1); | |
38 | + if (type) type->Print(indentLevel+1); | |
39 | + if (id) id->Print(indentLevel+1); | |
40 | + if (assignTo) assignTo->Print(indentLevel+1, "(initializer) "); | |
41 | +} | |
42 | + | |
43 | +FnDecl::FnDecl(Identifier *n, Type *r, List<VarDecl*> *d) : Decl(n) { | |
44 | + Assert(n != NULL && r!= NULL && d != NULL); | |
45 | + (returnType=r)->SetParent(this); | |
46 | + (formals=d)->SetParentAll(this); | |
47 | + body = NULL; | |
48 | + returnTypeq = NULL; | |
49 | +} | |
50 | + | |
51 | +FnDecl::FnDecl(Identifier *n, Type *r, TypeQualifier *rq, List<VarDecl*> *d) : Decl(n) { | |
52 | + Assert(n != NULL && r != NULL && rq != NULL&& d != NULL); | |
53 | + (returnType=r)->SetParent(this); | |
54 | + (returnTypeq=rq)->SetParent(this); | |
55 | + (formals=d)->SetParentAll(this); | |
56 | + body = NULL; | |
57 | +} | |
58 | + | |
59 | +void FnDecl::SetFunctionBody(Stmt *b) { | |
60 | + (body=b)->SetParent(this); | |
61 | +} | |
62 | + | |
63 | +void FnDecl::PrintChildren(int indentLevel) { | |
64 | + if (returnType) returnType->Print(indentLevel+1, "(return type) "); | |
65 | + if (id) id->Print(indentLevel+1); | |
66 | + if (formals) formals->PrintAll(indentLevel+1, "(formals) "); | |
67 | + if (body) body->Print(indentLevel+1, "(body) "); | |
68 | +} | |
69 | + |
ast_decl.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,92 @@ |
1 | +/* File: ast_decl.h | |
2 | + * ---------------- | |
3 | + * In our parse tree, Decl nodes are used to represent and | |
4 | + * manage declarations. There are 4 subclasses of the base class, | |
5 | + * specialized for declarations of variables, functions, classes, | |
6 | + * and interfaces. | |
7 | + * | |
8 | + * pp3: You will need to extend the Decl classes to implement | |
9 | + * semantic processing including detection of declaration conflicts | |
10 | + * and managing scoping issues. | |
11 | + */ | |
12 | + | |
13 | +#ifndef _H_ast_decl | |
14 | +#define _H_ast_decl | |
15 | + | |
16 | +#include "ast.h" | |
17 | +#include "list.h" | |
18 | +#include "ast_expr.h" | |
19 | + | |
20 | +class Type; | |
21 | +class TypeQualifier; | |
22 | +class NamedType; | |
23 | +class Identifier; | |
24 | +class Stmt; | |
25 | + | |
26 | +void yyerror(const char *msg); | |
27 | + | |
28 | +class Decl : public Node | |
29 | +{ | |
30 | + protected: | |
31 | + Identifier *id; | |
32 | + | |
33 | + public: | |
34 | + Decl() : id(NULL) {} | |
35 | + Decl(Identifier *name); | |
36 | + Identifier *GetIdentifier() const { return id; } | |
37 | + friend ostream& operator<<(ostream& out, Decl *d) { return out << d->id; } | |
38 | + | |
39 | +}; | |
40 | + | |
41 | +class VarDecl : public Decl | |
42 | +{ | |
43 | + protected: | |
44 | + Type *type; | |
45 | + TypeQualifier *typeq; | |
46 | + Expr *assignTo; | |
47 | + | |
48 | + public: | |
49 | + VarDecl() : type(NULL), typeq(NULL), assignTo(NULL) {} | |
50 | + VarDecl(Identifier *name, Type *type, Expr *assignTo = NULL); | |
51 | + VarDecl(Identifier *name, TypeQualifier *typeq, Expr *assignTo = NULL); | |
52 | + VarDecl(Identifier *name, Type *type, TypeQualifier *typeq, Expr *assignTo = NULL); | |
53 | + const char *GetPrintNameForNode() { return "VarDecl"; } | |
54 | + void PrintChildren(int indentLevel); | |
55 | + Type *GetType() const { return type; } | |
56 | +}; | |
57 | + | |
58 | +class VarDeclError : public VarDecl | |
59 | +{ | |
60 | + public: | |
61 | + VarDeclError() : VarDecl() { yyerror(this->GetPrintNameForNode()); }; | |
62 | + const char *GetPrintNameForNode() { return "VarDeclError"; } | |
63 | +}; | |
64 | + | |
65 | +class FnDecl : public Decl | |
66 | +{ | |
67 | + protected: | |
68 | + List<VarDecl*> *formals; | |
69 | + Type *returnType; | |
70 | + TypeQualifier *returnTypeq; | |
71 | + Stmt *body; | |
72 | + | |
73 | + public: | |
74 | + FnDecl() : Decl(), formals(NULL), returnType(NULL), returnTypeq(NULL), body(NULL) {} | |
75 | + FnDecl(Identifier *name, Type *returnType, List<VarDecl*> *formals); | |
76 | + FnDecl(Identifier *name, Type *returnType, TypeQualifier *returnTypeq, List<VarDecl*> *formals); | |
77 | + void SetFunctionBody(Stmt *b); | |
78 | + const char *GetPrintNameForNode() { return "FnDecl"; } | |
79 | + void PrintChildren(int indentLevel); | |
80 | + | |
81 | + Type *GetType() const { return returnType; } | |
82 | + List<VarDecl*> *GetFormals() {return formals;} | |
83 | +}; | |
84 | + | |
85 | +class FormalsError : public FnDecl | |
86 | +{ | |
87 | + public: | |
88 | + FormalsError() : FnDecl() { yyerror(this->GetPrintNameForNode()); } | |
89 | + const char *GetPrintNameForNode() { return "FormalsError"; } | |
90 | +}; | |
91 | + | |
92 | +#endif |
ast_expr.cc
View file @
c30bbd1
... | ... | @@ -0,0 +1,134 @@ |
1 | +/* File: ast_expr.cc | |
2 | + * ----------------- | |
3 | + * Implementation of expression node classes. | |
4 | + */ | |
5 | + | |
6 | +#include <string.h> | |
7 | +#include "ast_expr.h" | |
8 | +#include "ast_type.h" | |
9 | +#include "ast_decl.h" | |
10 | +#include "symtable.h" | |
11 | + | |
12 | +IntConstant::IntConstant(yyltype loc, int val) : Expr(loc) { | |
13 | + value = val; | |
14 | +} | |
15 | +void IntConstant::PrintChildren(int indentLevel) { | |
16 | + printf("%d", value); | |
17 | +} | |
18 | + | |
19 | +FloatConstant::FloatConstant(yyltype loc, double val) : Expr(loc) { | |
20 | + value = val; | |
21 | +} | |
22 | +void FloatConstant::PrintChildren(int indentLevel) { | |
23 | + printf("%g", value); | |
24 | +} | |
25 | + | |
26 | +BoolConstant::BoolConstant(yyltype loc, bool val) : Expr(loc) { | |
27 | + value = val; | |
28 | +} | |
29 | +void BoolConstant::PrintChildren(int indentLevel) { | |
30 | + printf("%s", value ? "true" : "false"); | |
31 | +} | |
32 | + | |
33 | +VarExpr::VarExpr(yyltype loc, Identifier *ident) : Expr(loc) { | |
34 | + Assert(ident != NULL); | |
35 | + this->id = ident; | |
36 | +} | |
37 | + | |
38 | +void VarExpr::PrintChildren(int indentLevel) { | |
39 | + id->Print(indentLevel+1); | |
40 | +} | |
41 | + | |
42 | +Operator::Operator(yyltype loc, const char *tok) : Node(loc) { | |
43 | + Assert(tok != NULL); | |
44 | + strncpy(tokenString, tok, sizeof(tokenString)); | |
45 | +} | |
46 | + | |
47 | +void Operator::PrintChildren(int indentLevel) { | |
48 | + printf("%s",tokenString); | |
49 | +} | |
50 | + | |
51 | +bool Operator::IsOp(const char *op) const { | |
52 | + return strcmp(tokenString, op) == 0; | |
53 | +} | |
54 | + | |
55 | +CompoundExpr::CompoundExpr(Expr *l, Operator *o, Expr *r) | |
56 | + : Expr(Join(l->GetLocation(), r->GetLocation())) { | |
57 | + Assert(l != NULL && o != NULL && r != NULL); | |
58 | + (op=o)->SetParent(this); | |
59 | + (left=l)->SetParent(this); | |
60 | + (right=r)->SetParent(this); | |
61 | +} | |
62 | + | |
63 | +CompoundExpr::CompoundExpr(Operator *o, Expr *r) | |
64 | + : Expr(Join(o->GetLocation(), r->GetLocation())) { | |
65 | + Assert(o != NULL && r != NULL); | |
66 | + left = NULL; | |
67 | + (op=o)->SetParent(this); | |
68 | + (right=r)->SetParent(this); | |
69 | +} | |
70 | + | |
71 | +CompoundExpr::CompoundExpr(Expr *l, Operator *o) | |
72 | + : Expr(Join(l->GetLocation(), o->GetLocation())) { | |
73 | + Assert(l != NULL && o != NULL); | |
74 | + (left=l)->SetParent(this); | |
75 | + (op=o)->SetParent(this); | |
76 | +} | |
77 | + | |
78 | +void CompoundExpr::PrintChildren(int indentLevel) { | |
79 | + if (left) left->Print(indentLevel+1); | |
80 | + op->Print(indentLevel+1); | |
81 | + if (right) right->Print(indentLevel+1); | |
82 | +} | |
83 | + | |
84 | +ConditionalExpr::ConditionalExpr(Expr *c, Expr *t, Expr *f) | |
85 | + : Expr(Join(c->GetLocation(), f->GetLocation())) { | |
86 | + Assert(c != NULL && t != NULL && f != NULL); | |
87 | + (cond=c)->SetParent(this); | |
88 | + (trueExpr=t)->SetParent(this); | |
89 | + (falseExpr=f)->SetParent(this); | |
90 | +} | |
91 | + | |
92 | +void ConditionalExpr::PrintChildren(int indentLevel) { | |
93 | + cond->Print(indentLevel+1, "(cond) "); | |
94 | + trueExpr->Print(indentLevel+1, "(true) "); | |
95 | + falseExpr->Print(indentLevel+1, "(false) "); | |
96 | +} | |
97 | +ArrayAccess::ArrayAccess(yyltype loc, Expr *b, Expr *s) : LValue(loc) { | |
98 | + (base=b)->SetParent(this); | |
99 | + (subscript=s)->SetParent(this); | |
100 | +} | |
101 | + | |
102 | +void ArrayAccess::PrintChildren(int indentLevel) { | |
103 | + base->Print(indentLevel+1); | |
104 | + subscript->Print(indentLevel+1, "(subscript) "); | |
105 | +} | |
106 | + | |
107 | +FieldAccess::FieldAccess(Expr *b, Identifier *f) | |
108 | + : LValue(b? Join(b->GetLocation(), f->GetLocation()) : *f->GetLocation()) { | |
109 | + Assert(f != NULL); // b can be be NULL (just means no explicit base) | |
110 | + base = b; | |
111 | + if (base) base->SetParent(this); | |
112 | + (field=f)->SetParent(this); | |
113 | +} | |
114 | + | |
115 | + | |
116 | +void FieldAccess::PrintChildren(int indentLevel) { | |
117 | + if (base) base->Print(indentLevel+1); | |
118 | + field->Print(indentLevel+1); | |
119 | +} | |
120 | + | |
121 | +Call::Call(yyltype loc, Expr *b, Identifier *f, List<Expr*> *a) : Expr(loc) { | |
122 | + Assert(f != NULL && a != NULL); // b can be be NULL (just means no explicit base) | |
123 | + base = b; | |
124 | + if (base) base->SetParent(this); | |
125 | + (field=f)->SetParent(this); | |
126 | + (actuals=a)->SetParentAll(this); | |
127 | +} | |
128 | + | |
129 | +void Call::PrintChildren(int indentLevel) { | |
130 | + if (base) base->Print(indentLevel+1); | |
131 | + if (field) field->Print(indentLevel+1); | |
132 | + if (actuals) actuals->PrintAll(indentLevel+1, "(actuals) "); | |
133 | +} | |
134 | + |
ast_expr.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,235 @@ |
1 | +/* File: ast_expr.h | |
2 | + * ---------------- | |
3 | + * The Expr class and its subclasses are used to represent | |
4 | + * expressions in the parse tree. For each expression in the | |
5 | + * language (add, call, New, etc.) there is a corresponding | |
6 | + * node class for that construct. | |
7 | + * | |
8 | + * pp3: You will need to extend the Expr classes to implement | |
9 | + * semantic analysis for rules pertaining to expressions. | |
10 | + */ | |
11 | + | |
12 | + | |
13 | +#ifndef _H_ast_expr | |
14 | +#define _H_ast_expr | |
15 | + | |
16 | +#include "ast.h" | |
17 | +#include "ast_stmt.h" | |
18 | +#include "list.h" | |
19 | +#include "ast_type.h" | |
20 | + | |
21 | +void yyerror(const char *msg); | |
22 | + | |
23 | +class Expr : public Stmt | |
24 | +{ | |
25 | + public: | |
26 | + Expr(yyltype loc) : Stmt(loc) {} | |
27 | + Expr() : Stmt() {} | |
28 | + | |
29 | + friend std::ostream& operator<< (std::ostream& stream, Expr * expr) { | |
30 | + return stream << expr->GetPrintNameForNode(); | |
31 | + } | |
32 | +}; | |
33 | + | |
34 | +class ExprError : public Expr | |
35 | +{ | |
36 | + public: | |
37 | + ExprError() : Expr() { yyerror(this->GetPrintNameForNode()); } | |
38 | + const char *GetPrintNameForNode() { return "ExprError"; } | |
39 | +}; | |
40 | + | |
41 | +/* This node type is used for those places where an expression is optional. | |
42 | + * We could use a NULL pointer, but then it adds a lot of checking for | |
43 | + * NULL. By using a valid, but no-op, node, we save that trouble */ | |
44 | +class EmptyExpr : public Expr | |
45 | +{ | |
46 | + public: | |
47 | + const char *GetPrintNameForNode() { return "Empty"; } | |
48 | +}; | |
49 | + | |
50 | +class IntConstant : public Expr | |
51 | +{ | |
52 | + protected: | |
53 | + int value; | |
54 | + | |
55 | + public: | |
56 | + IntConstant(yyltype loc, int val); | |
57 | + const char *GetPrintNameForNode() { return "IntConstant"; } | |
58 | + void PrintChildren(int indentLevel); | |
59 | +}; | |
60 | + | |
61 | +class FloatConstant: public Expr | |
62 | +{ | |
63 | + protected: | |
64 | + double value; | |
65 | + | |
66 | + public: | |
67 | + FloatConstant(yyltype loc, double val); | |
68 | + const char *GetPrintNameForNode() { return "FloatConstant"; } | |
69 | + void PrintChildren(int indentLevel); | |
70 | +}; | |
71 | + | |
72 | +class BoolConstant : public Expr | |
73 | +{ | |
74 | + protected: | |
75 | + bool value; | |
76 | + | |
77 | + public: | |
78 | + BoolConstant(yyltype loc, bool val); | |
79 | + const char *GetPrintNameForNode() { return "BoolConstant"; } | |
80 | + void PrintChildren(int indentLevel); | |
81 | +}; | |
82 | + | |
83 | +class VarExpr : public Expr | |
84 | +{ | |
85 | + protected: | |
86 | + Identifier *id; | |
87 | + | |
88 | + public: | |
89 | + VarExpr(yyltype loc, Identifier *id); | |
90 | + const char *GetPrintNameForNode() { return "VarExpr"; } | |
91 | + void PrintChildren(int indentLevel); | |
92 | + Identifier *GetIdentifier() {return id;} | |
93 | +}; | |
94 | + | |
95 | +class Operator : public Node | |
96 | +{ | |
97 | + protected: | |
98 | + char tokenString[4]; | |
99 | + | |
100 | + public: | |
101 | + Operator(yyltype loc, const char *tok); | |
102 | + const char *GetPrintNameForNode() { return "Operator"; } | |
103 | + void PrintChildren(int indentLevel); | |
104 | + friend ostream& operator<<(ostream& out, Operator *o) { return out << o->tokenString; } | |
105 | + bool IsOp(const char *op) const; | |
106 | + }; | |
107 | + | |
108 | +class CompoundExpr : public Expr | |
109 | +{ | |
110 | + protected: | |
111 | + Operator *op; | |
112 | + Expr *left, *right; // left will be NULL if unary | |
113 | + | |
114 | + public: | |
115 | + CompoundExpr(Expr *lhs, Operator *op, Expr *rhs); // for binary | |
116 | + CompoundExpr(Operator *op, Expr *rhs); // for unary | |
117 | + CompoundExpr(Expr *lhs, Operator *op); // for unary | |
118 | + void PrintChildren(int indentLevel); | |
119 | +}; | |
120 | + | |
121 | +class ArithmeticExpr : public CompoundExpr | |
122 | +{ | |
123 | + public: | |
124 | + ArithmeticExpr(Expr *lhs, Operator *op, Expr *rhs) : CompoundExpr(lhs,op,rhs) {} | |
125 | + ArithmeticExpr(Operator *op, Expr *rhs) : CompoundExpr(op,rhs) {} | |
126 | + const char *GetPrintNameForNode() { return "ArithmeticExpr"; } | |
127 | +}; | |
128 | + | |
129 | +class RelationalExpr : public CompoundExpr | |
130 | +{ | |
131 | + public: | |
132 | + RelationalExpr(Expr *lhs, Operator *op, Expr *rhs) : CompoundExpr(lhs,op,rhs) {} | |
133 | + const char *GetPrintNameForNode() { return "RelationalExpr"; } | |
134 | +}; | |
135 | + | |
136 | +class EqualityExpr : public CompoundExpr | |
137 | +{ | |
138 | + public: | |
139 | + EqualityExpr(Expr *lhs, Operator *op, Expr *rhs) : CompoundExpr(lhs,op,rhs) {} | |
140 | + const char *GetPrintNameForNode() { return "EqualityExpr"; } | |
141 | +}; | |
142 | + | |
143 | +class LogicalExpr : public CompoundExpr | |
144 | +{ | |
145 | + public: | |
146 | + LogicalExpr(Expr *lhs, Operator *op, Expr *rhs) : CompoundExpr(lhs,op,rhs) {} | |
147 | + LogicalExpr(Operator *op, Expr *rhs) : CompoundExpr(op,rhs) {} | |
148 | + const char *GetPrintNameForNode() { return "LogicalExpr"; } | |
149 | +}; | |
150 | + | |
151 | +class AssignExpr : public CompoundExpr | |
152 | +{ | |
153 | + public: | |
154 | + AssignExpr(Expr *lhs, Operator *op, Expr *rhs) : CompoundExpr(lhs,op,rhs) {} | |
155 | + const char *GetPrintNameForNode() { return "AssignExpr"; } | |
156 | +}; | |
157 | + | |
158 | +class PostfixExpr : public CompoundExpr | |
159 | +{ | |
160 | + public: | |
161 | + PostfixExpr(Expr *lhs, Operator *op) : CompoundExpr(lhs,op) {} | |
162 | + const char *GetPrintNameForNode() { return "PostfixExpr"; } | |
163 | + | |
164 | +}; | |
165 | + | |
166 | +class ConditionalExpr : public Expr | |
167 | +{ | |
168 | + protected: | |
169 | + Expr *cond, *trueExpr, *falseExpr; | |
170 | + public: | |
171 | + ConditionalExpr(Expr *c, Expr *t, Expr *f); | |
172 | + void PrintChildren(int indentLevel); | |
173 | + const char *GetPrintNameForNode() { return "ConditionalExpr"; } | |
174 | +}; | |
175 | + | |
176 | +class LValue : public Expr | |
177 | +{ | |
178 | + public: | |
179 | + LValue(yyltype loc) : Expr(loc) {} | |
180 | +}; | |
181 | + | |
182 | +class ArrayAccess : public LValue | |
183 | +{ | |
184 | + protected: | |
185 | + Expr *base, *subscript; | |
186 | + | |
187 | + public: | |
188 | + ArrayAccess(yyltype loc, Expr *base, Expr *subscript); | |
189 | + const char *GetPrintNameForNode() { return "ArrayAccess"; } | |
190 | + void PrintChildren(int indentLevel); | |
191 | +}; | |
192 | + | |
193 | +/* Note that field access is used both for qualified names | |
194 | + * base.field and just field without qualification. We don't | |
195 | + * know for sure whether there is an implicit "this." in | |
196 | + * front until later on, so we use one node type for either | |
197 | + * and sort it out later. */ | |
198 | +class FieldAccess : public LValue | |
199 | +{ | |
200 | + protected: | |
201 | + Expr *base; // will be NULL if no explicit base | |
202 | + Identifier *field; | |
203 | + | |
204 | + public: | |
205 | + FieldAccess(Expr *base, Identifier *field); //ok to pass NULL base | |
206 | + const char *GetPrintNameForNode() { return "FieldAccess"; } | |
207 | + void PrintChildren(int indentLevel); | |
208 | +}; | |
209 | + | |
210 | +/* Like field access, call is used both for qualified base.field() | |
211 | + * and unqualified field(). We won't figure out until later | |
212 | + * whether we need implicit "this." so we use one node type for either | |
213 | + * and sort it out later. */ | |
214 | +class Call : public Expr | |
215 | +{ | |
216 | + protected: | |
217 | + Expr *base; // will be NULL if no explicit base | |
218 | + Identifier *field; | |
219 | + List<Expr*> *actuals; | |
220 | + | |
221 | + public: | |
222 | + Call() : Expr(), base(NULL), field(NULL), actuals(NULL) {} | |
223 | + Call(yyltype loc, Expr *base, Identifier *field, List<Expr*> *args); | |
224 | + const char *GetPrintNameForNode() { return "Call"; } | |
225 | + void PrintChildren(int indentLevel); | |
226 | +}; | |
227 | + | |
228 | +class ActualsError : public Call | |
229 | +{ | |
230 | + public: | |
231 | + ActualsError() : Call() { yyerror(this->GetPrintNameForNode()); } | |
232 | + const char *GetPrintNameForNode() { return "ActualsError"; } | |
233 | +}; | |
234 | + | |
235 | +#endif |
ast_stmt.cc
View file @
c30bbd1
... | ... | @@ -0,0 +1,161 @@ |
1 | +/* File: ast_stmt.cc | |
2 | + * ----------------- | |
3 | + * Implementation of statement node classes. | |
4 | + */ | |
5 | +#include "ast_stmt.h" | |
6 | +#include "ast_type.h" | |
7 | +#include "ast_decl.h" | |
8 | +#include "ast_expr.h" | |
9 | +#include "symtable.h" | |
10 | + | |
11 | +#include "irgen.h" | |
12 | +#include "llvm/Bitcode/ReaderWriter.h" | |
13 | +#include "llvm/Support/raw_ostream.h" | |
14 | + | |
15 | + | |
16 | +Program::Program(List<Decl*> *d) { | |
17 | + Assert(d != NULL); | |
18 | + (decls=d)->SetParentAll(this); | |
19 | +} | |
20 | + | |
21 | +void Program::PrintChildren(int indentLevel) { | |
22 | + decls->PrintAll(indentLevel+1); | |
23 | + printf("\n"); | |
24 | +} | |
25 | + | |
26 | +void Program::Emit() { | |
27 | + // TODO: | |
28 | + // This is just a reference for you to get started | |
29 | + // | |
30 | + // You can use this as a template and create Emit() function | |
31 | + // for individual node to fill in the module structure and instructions. | |
32 | + // | |
33 | + IRGenerator irgen; | |
34 | + llvm::Module *mod = irgen.GetOrCreateModule("Name_the_Module.bc"); | |
35 | + | |
36 | + // create a function signature | |
37 | + std::vector<llvm::Type *> argTypes; | |
38 | + llvm::Type *intTy = irgen.GetIntType(); | |
39 | + argTypes.push_back(intTy); | |
40 | + llvm::ArrayRef<llvm::Type *> argArray(argTypes); | |
41 | + llvm::FunctionType *funcTy = llvm::FunctionType::get(intTy, argArray, false); | |
42 | + | |
43 | + // llvm::Function *f = llvm::cast<llvm::Function>(mod->getOrInsertFunction("foo", intTy, intTy, (Type *)0)); | |
44 | + llvm::Function *f = llvm::cast<llvm::Function>(mod->getOrInsertFunction("Name_the_function", funcTy)); | |
45 | + llvm::Argument *arg = f->arg_begin(); | |
46 | + arg->setName("x"); | |
47 | + | |
48 | + // insert a block into the runction | |
49 | + llvm::LLVMContext *context = irgen.GetContext(); | |
50 | + llvm::BasicBlock *bb = llvm::BasicBlock::Create(*context, "entry", f); | |
51 | + | |
52 | + // create a return instruction | |
53 | + llvm::Value *val = llvm::ConstantInt::get(intTy, 1); | |
54 | + llvm::Value *sum = llvm::BinaryOperator::CreateAdd(arg, val, "", bb); | |
55 | + llvm::ReturnInst::Create(*context, sum, bb); | |
56 | + | |
57 | + // write the BC into standard output | |
58 | + llvm::WriteBitcodeToFile(mod, llvm::outs()); | |
59 | +} | |
60 | + | |
61 | +StmtBlock::StmtBlock(List<VarDecl*> *d, List<Stmt*> *s) { | |
62 | + Assert(d != NULL && s != NULL); | |
63 | + (decls=d)->SetParentAll(this); | |
64 | + (stmts=s)->SetParentAll(this); | |
65 | +} | |
66 | + | |
67 | +void StmtBlock::PrintChildren(int indentLevel) { | |
68 | + decls->PrintAll(indentLevel+1); | |
69 | + stmts->PrintAll(indentLevel+1); | |
70 | +} | |
71 | + | |
72 | +DeclStmt::DeclStmt(Decl *d) { | |
73 | + Assert(d != NULL); | |
74 | + (decl=d)->SetParent(this); | |
75 | +} | |
76 | + | |
77 | +void DeclStmt::PrintChildren(int indentLevel) { | |
78 | + decl->Print(indentLevel+1); | |
79 | +} | |
80 | + | |
81 | +ConditionalStmt::ConditionalStmt(Expr *t, Stmt *b) { | |
82 | + Assert(t != NULL && b != NULL); | |
83 | + (test=t)->SetParent(this); | |
84 | + (body=b)->SetParent(this); | |
85 | +} | |
86 | + | |
87 | +ForStmt::ForStmt(Expr *i, Expr *t, Expr *s, Stmt *b): LoopStmt(t, b) { | |
88 | + Assert(i != NULL && t != NULL && b != NULL); | |
89 | + (init=i)->SetParent(this); | |
90 | + step = s; | |
91 | + if ( s ) | |
92 | + (step=s)->SetParent(this); | |
93 | +} | |
94 | + | |
95 | +void ForStmt::PrintChildren(int indentLevel) { | |
96 | + init->Print(indentLevel+1, "(init) "); | |
97 | + test->Print(indentLevel+1, "(test) "); | |
98 | + if ( step ) | |
99 | + step->Print(indentLevel+1, "(step) "); | |
100 | + body->Print(indentLevel+1, "(body) "); | |
101 | +} | |
102 | + | |
103 | +void WhileStmt::PrintChildren(int indentLevel) { | |
104 | + test->Print(indentLevel+1, "(test) "); | |
105 | + body->Print(indentLevel+1, "(body) "); | |
106 | +} | |
107 | + | |
108 | +IfStmt::IfStmt(Expr *t, Stmt *tb, Stmt *eb): ConditionalStmt(t, tb) { | |
109 | + Assert(t != NULL && tb != NULL); // else can be NULL | |
110 | + elseBody = eb; | |
111 | + if (elseBody) elseBody->SetParent(this); | |
112 | +} | |
113 | + | |
114 | +void IfStmt::PrintChildren(int indentLevel) { | |
115 | + if (test) test->Print(indentLevel+1, "(test) "); | |
116 | + if (body) body->Print(indentLevel+1, "(then) "); | |
117 | + if (elseBody) elseBody->Print(indentLevel+1, "(else) "); | |
118 | +} | |
119 | + | |
120 | + | |
121 | +ReturnStmt::ReturnStmt(yyltype loc, Expr *e) : Stmt(loc) { | |
122 | + expr = e; | |
123 | + if (e != NULL) expr->SetParent(this); | |
124 | +} | |
125 | + | |
126 | +void ReturnStmt::PrintChildren(int indentLevel) { | |
127 | + if ( expr ) | |
128 | + expr->Print(indentLevel+1); | |
129 | +} | |
130 | + | |
131 | +SwitchLabel::SwitchLabel(Expr *l, Stmt *s) { | |
132 | + Assert(l != NULL && s != NULL); | |
133 | + (label=l)->SetParent(this); | |
134 | + (stmt=s)->SetParent(this); | |
135 | +} | |
136 | + | |
137 | +SwitchLabel::SwitchLabel(Stmt *s) { | |
138 | + Assert(s != NULL); | |
139 | + label = NULL; | |
140 | + (stmt=s)->SetParent(this); | |
141 | +} | |
142 | + | |
143 | +void SwitchLabel::PrintChildren(int indentLevel) { | |
144 | + if (label) label->Print(indentLevel+1); | |
145 | + if (stmt) stmt->Print(indentLevel+1); | |
146 | +} | |
147 | + | |
148 | +SwitchStmt::SwitchStmt(Expr *e, List<Stmt *> *c, Default *d) { | |
149 | + Assert(e != NULL && c != NULL && c->NumElements() != 0 ); | |
150 | + (expr=e)->SetParent(this); | |
151 | + (cases=c)->SetParentAll(this); | |
152 | + def = d; | |
153 | + if (def) def->SetParent(this); | |
154 | +} | |
155 | + | |
156 | +void SwitchStmt::PrintChildren(int indentLevel) { | |
157 | + if (expr) expr->Print(indentLevel+1); | |
158 | + if (cases) cases->PrintAll(indentLevel+1); | |
159 | + if (def) def->Print(indentLevel+1); | |
160 | +} | |
161 | + |
ast_stmt.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,208 @@ |
1 | +/* File: ast_stmt.h | |
2 | + * ---------------- | |
3 | + * The Stmt class and its subclasses are used to represent | |
4 | + * statements in the parse tree. For each statment in the | |
5 | + * language (for, if, return, etc.) there is a corresponding | |
6 | + * node class for that construct. | |
7 | + * | |
8 | + * pp3: You will need to extend the Stmt classes to generate | |
9 | + * LLVM IR instructions. | |
10 | + */ | |
11 | + | |
12 | + | |
13 | +#ifndef _H_ast_stmt | |
14 | +#define _H_ast_stmt | |
15 | + | |
16 | +#include "list.h" | |
17 | +#include "ast.h" | |
18 | + | |
19 | +class Decl; | |
20 | +class VarDecl; | |
21 | +class Expr; | |
22 | +class IntConstant; | |
23 | + | |
24 | +void yyerror(const char *msg); | |
25 | + | |
26 | +class Program : public Node | |
27 | +{ | |
28 | + protected: | |
29 | + List<Decl*> *decls; | |
30 | + | |
31 | + public: | |
32 | + Program(List<Decl*> *declList); | |
33 | + const char *GetPrintNameForNode() { return "Program"; } | |
34 | + void PrintChildren(int indentLevel); | |
35 | + virtual void Emit(); | |
36 | +}; | |
37 | + | |
38 | +class Stmt : public Node | |
39 | +{ | |
40 | + public: | |
41 | + Stmt() : Node() {} | |
42 | + Stmt(yyltype loc) : Node(loc) {} | |
43 | +}; | |
44 | + | |
45 | +class StmtBlock : public Stmt | |
46 | +{ | |
47 | + protected: | |
48 | + List<VarDecl*> *decls; | |
49 | + List<Stmt*> *stmts; | |
50 | + | |
51 | + public: | |
52 | + StmtBlock(List<VarDecl*> *variableDeclarations, List<Stmt*> *statements); | |
53 | + const char *GetPrintNameForNode() { return "StmtBlock"; } | |
54 | + void PrintChildren(int indentLevel); | |
55 | +}; | |
56 | + | |
57 | +class DeclStmt: public Stmt | |
58 | +{ | |
59 | + protected: | |
60 | + Decl* decl; | |
61 | + | |
62 | + public: | |
63 | + DeclStmt(Decl *d); | |
64 | + const char *GetPrintNameForNode() { return "DeclStmt"; } | |
65 | + void PrintChildren(int indentLevel); | |
66 | + | |
67 | +}; | |
68 | + | |
69 | +class ConditionalStmt : public Stmt | |
70 | +{ | |
71 | + protected: | |
72 | + Expr *test; | |
73 | + Stmt *body; | |
74 | + | |
75 | + public: | |
76 | + ConditionalStmt() : Stmt(), test(NULL), body(NULL) {} | |
77 | + ConditionalStmt(Expr *testExpr, Stmt *body); | |
78 | + | |
79 | +}; | |
80 | + | |
81 | +class LoopStmt : public ConditionalStmt | |
82 | +{ | |
83 | + public: | |
84 | + LoopStmt(Expr *testExpr, Stmt *body) | |
85 | + : ConditionalStmt(testExpr, body) {} | |
86 | +}; | |
87 | + | |
88 | +class ForStmt : public LoopStmt | |
89 | +{ | |
90 | + protected: | |
91 | + Expr *init, *step; | |
92 | + | |
93 | + public: | |
94 | + ForStmt(Expr *init, Expr *test, Expr *step, Stmt *body); | |
95 | + const char *GetPrintNameForNode() { return "ForStmt"; } | |
96 | + void PrintChildren(int indentLevel); | |
97 | + | |
98 | +}; | |
99 | + | |
100 | +class WhileStmt : public LoopStmt | |
101 | +{ | |
102 | + public: | |
103 | + WhileStmt(Expr *test, Stmt *body) : LoopStmt(test, body) {} | |
104 | + const char *GetPrintNameForNode() { return "WhileStmt"; } | |
105 | + void PrintChildren(int indentLevel); | |
106 | + | |
107 | +}; | |
108 | + | |
109 | +class IfStmt : public ConditionalStmt | |
110 | +{ | |
111 | + protected: | |
112 | + Stmt *elseBody; | |
113 | + | |
114 | + public: | |
115 | + IfStmt() : ConditionalStmt(), elseBody(NULL) {} | |
116 | + IfStmt(Expr *test, Stmt *thenBody, Stmt *elseBody); | |
117 | + const char *GetPrintNameForNode() { return "IfStmt"; } | |
118 | + void PrintChildren(int indentLevel); | |
119 | + | |
120 | +}; | |
121 | + | |
122 | +class IfStmtExprError : public IfStmt | |
123 | +{ | |
124 | + public: | |
125 | + IfStmtExprError() : IfStmt() { yyerror(this->GetPrintNameForNode()); } | |
126 | + const char *GetPrintNameForNode() { return "IfStmtExprError"; } | |
127 | +}; | |
128 | + | |
129 | +class BreakStmt : public Stmt | |
130 | +{ | |
131 | + public: | |
132 | + BreakStmt(yyltype loc) : Stmt(loc) {} | |
133 | + const char *GetPrintNameForNode() { return "BreakStmt"; } | |
134 | + | |
135 | +}; | |
136 | + | |
137 | +class ContinueStmt : public Stmt | |
138 | +{ | |
139 | + public: | |
140 | + ContinueStmt(yyltype loc) : Stmt(loc) {} | |
141 | + const char *GetPrintNameForNode() { return "ContinueStmt"; } | |
142 | + | |
143 | +}; | |
144 | + | |
145 | +class ReturnStmt : public Stmt | |
146 | +{ | |
147 | + protected: | |
148 | + Expr *expr; | |
149 | + | |
150 | + public: | |
151 | + ReturnStmt(yyltype loc, Expr *expr = NULL); | |
152 | + const char *GetPrintNameForNode() { return "ReturnStmt"; } | |
153 | + void PrintChildren(int indentLevel); | |
154 | + | |
155 | +}; | |
156 | + | |
157 | +class SwitchLabel : public Stmt | |
158 | +{ | |
159 | + protected: | |
160 | + Expr *label; | |
161 | + Stmt *stmt; | |
162 | + | |
163 | + public: | |
164 | + SwitchLabel() { label = NULL; stmt = NULL; } | |
165 | + SwitchLabel(Expr *label, Stmt *stmt); | |
166 | + SwitchLabel(Stmt *stmt); | |
167 | + void PrintChildren(int indentLevel); | |
168 | + | |
169 | +}; | |
170 | + | |
171 | +class Case : public SwitchLabel | |
172 | +{ | |
173 | + public: | |
174 | + Case() : SwitchLabel() {} | |
175 | + Case(Expr *label, Stmt *stmt) : SwitchLabel(label, stmt) {} | |
176 | + const char *GetPrintNameForNode() { return "Case"; } | |
177 | +}; | |
178 | + | |
179 | +class Default : public SwitchLabel | |
180 | +{ | |
181 | + public: | |
182 | + Default(Stmt *stmt) : SwitchLabel(stmt) {} | |
183 | + const char *GetPrintNameForNode() { return "Default"; } | |
184 | +}; | |
185 | + | |
186 | +class SwitchStmt : public Stmt | |
187 | +{ | |
188 | + protected: | |
189 | + Expr *expr; | |
190 | + List<Stmt*> *cases; | |
191 | + Default *def; | |
192 | + | |
193 | + public: | |
194 | + SwitchStmt() : expr(NULL), cases(NULL), def(NULL) {} | |
195 | + SwitchStmt(Expr *expr, List<Stmt*> *cases, Default *def); | |
196 | + virtual const char *GetPrintNameForNode() { return "SwitchStmt"; } | |
197 | + void PrintChildren(int indentLevel); | |
198 | + | |
199 | +}; | |
200 | + | |
201 | +class SwitchStmtError : public SwitchStmt | |
202 | +{ | |
203 | + public: | |
204 | + SwitchStmtError(const char * msg) { yyerror(msg); } | |
205 | + const char *GetPrintNameForNode() { return "SwitchStmtError"; } | |
206 | +}; | |
207 | + | |
208 | +#endif |
ast_type.cc
View file @
c30bbd1
... | ... | @@ -0,0 +1,101 @@ |
1 | +/* File: ast_type.cc | |
2 | + * ----------------- | |
3 | + * Implementation of type node classes. | |
4 | + */ | |
5 | + | |
6 | +#include <string.h> | |
7 | +#include "ast_type.h" | |
8 | +#include "ast_decl.h" | |
9 | + | |
10 | +/* Class constants | |
11 | + * --------------- | |
12 | + * These are public constants for the built-in base types (int, double, etc.) | |
13 | + * They can be accessed with the syntax Type::intType. This allows you to | |
14 | + * directly access them and share the built-in types where needed rather that | |
15 | + * creates lots of copies. | |
16 | + */ | |
17 | + | |
18 | +Type *Type::intType = new Type("int"); | |
19 | +Type *Type::floatType = new Type("float"); | |
20 | +Type *Type::voidType = new Type("void"); | |
21 | +Type *Type::boolType = new Type("bool"); | |
22 | +Type *Type::mat2Type = new Type("mat2"); | |
23 | +Type *Type::mat3Type = new Type("mat3"); | |
24 | +Type *Type::mat4Type = new Type("mat4"); | |
25 | +Type *Type::vec2Type = new Type("vec2"); | |
26 | +Type *Type::vec3Type = new Type("vec3"); | |
27 | +Type *Type::vec4Type = new Type("vec4"); | |
28 | +Type *Type::ivec2Type = new Type("ivec2"); | |
29 | +Type *Type::ivec3Type = new Type("ivec3"); | |
30 | +Type *Type::ivec4Type = new Type("ivec4"); | |
31 | +Type *Type::bvec2Type = new Type("bvec2"); | |
32 | +Type *Type::bvec3Type = new Type("bvec3"); | |
33 | +Type *Type::bvec4Type = new Type("bvec4"); | |
34 | +Type *Type::uintType = new Type("uint"); | |
35 | +Type *Type::uvec2Type = new Type("uvec2"); | |
36 | +Type *Type::uvec3Type = new Type("uvec3"); | |
37 | +Type *Type::uvec4Type = new Type("uvec4"); | |
38 | +Type *Type::errorType = new Type("error"); | |
39 | + | |
40 | +TypeQualifier *TypeQualifier::inTypeQualifier = new TypeQualifier("in"); | |
41 | +TypeQualifier *TypeQualifier::outTypeQualifier = new TypeQualifier("out"); | |
42 | +TypeQualifier *TypeQualifier::constTypeQualifier = new TypeQualifier("const"); | |
43 | +TypeQualifier *TypeQualifier::uniformTypeQualifier = new TypeQualifier("uniform"); | |
44 | + | |
45 | +Type::Type(const char *n) { | |
46 | + Assert(n); | |
47 | + typeName = strdup(n); | |
48 | +} | |
49 | + | |
50 | +void Type::PrintChildren(int indentLevel) { | |
51 | + printf("%s", typeName); | |
52 | +} | |
53 | + | |
54 | +TypeQualifier::TypeQualifier(const char *n) { | |
55 | + Assert(n); | |
56 | + typeQualifierName = strdup(n); | |
57 | +} | |
58 | + | |
59 | +void TypeQualifier::PrintChildren(int indentLevel) { | |
60 | + printf("%s", typeQualifierName); | |
61 | +} | |
62 | + | |
63 | +bool Type::IsNumeric() { | |
64 | + return this->IsEquivalentTo(Type::intType) || this->IsEquivalentTo(Type::floatType); | |
65 | +} | |
66 | + | |
67 | +bool Type::IsVector() { | |
68 | + return this->IsEquivalentTo(Type::vec2Type) || | |
69 | + this->IsEquivalentTo(Type::vec3Type) || | |
70 | + this->IsEquivalentTo(Type::vec4Type); | |
71 | +} | |
72 | + | |
73 | +bool Type::IsMatrix() { | |
74 | + return this->IsEquivalentTo(Type::mat2Type) || | |
75 | + this->IsEquivalentTo(Type::mat3Type) || | |
76 | + this->IsEquivalentTo(Type::mat4Type); | |
77 | +} | |
78 | + | |
79 | +bool Type::IsError() { | |
80 | + return this->IsEquivalentTo(Type::errorType); | |
81 | +} | |
82 | + | |
83 | +NamedType::NamedType(Identifier *i) : Type(*i->GetLocation()) { | |
84 | + Assert(i != NULL); | |
85 | + (id=i)->SetParent(this); | |
86 | +} | |
87 | + | |
88 | +void NamedType::PrintChildren(int indentLevel) { | |
89 | + id->Print(indentLevel+1); | |
90 | +} | |
91 | + | |
92 | +ArrayType::ArrayType(yyltype loc, Type *et, int ec) : Type(loc) { | |
93 | + Assert(et != NULL); | |
94 | + (elemType=et)->SetParent(this); | |
95 | + elemCount=ec; | |
96 | +} | |
97 | +void ArrayType::PrintChildren(int indentLevel) { | |
98 | + elemType->Print(indentLevel+1); | |
99 | +} | |
100 | + | |
101 | + |
ast_type.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,96 @@ |
1 | +/* File: ast_type.h | |
2 | + * ---------------- | |
3 | + * In our parse tree, Type nodes are used to represent and | |
4 | + * store type information. The base Type class is used | |
5 | + * for built-in types, the NamedType for classes and interfaces, | |
6 | + * and the ArrayType for arrays of other types. | |
7 | + * | |
8 | + * pp3: You will need to extend the Type classes to implement | |
9 | + * the type system and rules for type equivalency and compatibility. | |
10 | + */ | |
11 | + | |
12 | +#ifndef _H_ast_type | |
13 | +#define _H_ast_type | |
14 | + | |
15 | +#include "ast.h" | |
16 | +#include "list.h" | |
17 | +#include <iostream> | |
18 | + | |
19 | +using namespace std; | |
20 | + | |
21 | +class TypeQualifier : public Node | |
22 | +{ | |
23 | + protected: | |
24 | + char *typeQualifierName; | |
25 | + | |
26 | + public : | |
27 | + static TypeQualifier *inTypeQualifier, *outTypeQualifier, *constTypeQualifier, *uniformTypeQualifier; | |
28 | + | |
29 | + TypeQualifier(yyltype loc) : Node(loc) {} | |
30 | + TypeQualifier(const char *str); | |
31 | + | |
32 | + const char *GetPrintNameForNode() { return "TypeQualifier"; } | |
33 | + void PrintChildren(int indentLevel); | |
34 | +}; | |
35 | + | |
36 | +class Type : public Node | |
37 | +{ | |
38 | + protected: | |
39 | + char *typeName; | |
40 | + | |
41 | + public : | |
42 | + static Type *intType, *uintType,*floatType, *boolType, *voidType, | |
43 | + *vec2Type, *vec3Type, *vec4Type, | |
44 | + *mat2Type, *mat3Type, *mat4Type, | |
45 | + *ivec2Type, *ivec3Type, *ivec4Type, | |
46 | + *bvec2Type, *bvec3Type, *bvec4Type, | |
47 | + *uvec2Type, *uvec3Type,*uvec4Type, | |
48 | + *errorType; | |
49 | + | |
50 | + Type(yyltype loc) : Node(loc) {} | |
51 | + Type(const char *str); | |
52 | + | |
53 | + const char *GetPrintNameForNode() { return "Type"; } | |
54 | + void PrintChildren(int indentLevel); | |
55 | + | |
56 | + virtual void PrintToStream(ostream& out) { out << typeName; } | |
57 | + friend ostream& operator<<(ostream& out, Type *t) { t->PrintToStream(out); return out; } | |
58 | + virtual bool IsEquivalentTo(Type *other) { return (this == other); } | |
59 | + virtual bool IsConvertibleTo(Type *other) { return (this == other || this == errorType); } | |
60 | + bool IsNumeric(); | |
61 | + bool IsVector(); | |
62 | + bool IsMatrix(); | |
63 | + bool IsError(); | |
64 | +}; | |
65 | + | |
66 | + | |
67 | +class NamedType : public Type | |
68 | +{ | |
69 | + protected: | |
70 | + Identifier *id; | |
71 | + | |
72 | + public: | |
73 | + NamedType(Identifier *i); | |
74 | + | |
75 | + const char *GetPrintNameForNode() { return "NamedType"; } | |
76 | + void PrintChildren(int indentLevel); | |
77 | + void PrintToStream(ostream& out) { out << id; } | |
78 | +}; | |
79 | + | |
80 | +class ArrayType : public Type | |
81 | +{ | |
82 | + protected: | |
83 | + Type *elemType; | |
84 | + int elemCount; | |
85 | + | |
86 | + public: | |
87 | + ArrayType(yyltype loc, Type *elemType, int elemCount); | |
88 | + | |
89 | + const char *GetPrintNameForNode() { return "ArrayType"; } | |
90 | + void PrintChildren(int indentLevel); | |
91 | + void PrintToStream(ostream& out) { out << elemType << "[]"; } | |
92 | + Type *GetElemType() {return elemType;} | |
93 | +}; | |
94 | + | |
95 | + | |
96 | +#endif |
errors.cc
View file @
c30bbd1
... | ... | @@ -0,0 +1,208 @@ |
1 | +/** | |
2 | + * File: errors.cc | |
3 | + * --------------- | |
4 | + * Implementation for error-reporting class. | |
5 | + */ | |
6 | + | |
7 | +#include "errors.h" | |
8 | +#include <sstream> | |
9 | +#include <stdarg.h> | |
10 | +#include <stdio.h> | |
11 | + | |
12 | +using namespace std; | |
13 | + | |
14 | +#include "scanner.h" // for GetLineNumbered | |
15 | +#include "ast_type.h" | |
16 | +#include "ast_expr.h" | |
17 | +#include "ast_stmt.h" | |
18 | +#include "ast_decl.h" | |
19 | + | |
20 | +int ReportError::numErrors = 0; | |
21 | + | |
22 | +void ReportError::UnderlineErrorInLine(const char *line, yyltype *pos) { | |
23 | + if (!line) return; | |
24 | + cerr << line << endl; | |
25 | + for (int i = 1; i <= pos->last_column; i++) | |
26 | + cerr << (i >= pos->first_column ? '^' : ' '); | |
27 | + cerr << endl; | |
28 | +} | |
29 | + | |
30 | + | |
31 | + | |
32 | +void ReportError::OutputError(yyltype *loc, string msg) { | |
33 | + numErrors++; | |
34 | + fflush(stdout); // make sure any buffered text has been output | |
35 | + if (loc) { | |
36 | + cerr << endl << "*** Error line " << loc->first_line << "." << endl; | |
37 | + UnderlineErrorInLine(GetLineNumbered(loc->first_line), loc); | |
38 | + } else | |
39 | + cerr << endl << "*** Error." << endl; | |
40 | + cerr << "*** " << msg << endl << endl; | |
41 | +} | |
42 | + | |
43 | + | |
44 | +void ReportError::Formatted(yyltype *loc, const char *format, ...) { | |
45 | + va_list args; | |
46 | + char errbuf[2048]; | |
47 | + | |
48 | + va_start(args, format); | |
49 | + vsprintf(errbuf,format, args); | |
50 | + va_end(args); | |
51 | + OutputError(loc, errbuf); | |
52 | +} | |
53 | + | |
54 | +void ReportError::UntermComment() { | |
55 | + OutputError(NULL, "Input ends with unterminated comment"); | |
56 | +} | |
57 | + | |
58 | + | |
59 | +void ReportError::LongIdentifier(yyltype *loc, const char *ident) { | |
60 | + ostringstream s; | |
61 | + s << "Identifier too long: \"" << ident << "\""; | |
62 | + OutputError(loc, s.str()); | |
63 | +} | |
64 | + | |
65 | +void ReportError::UntermString(yyltype *loc, const char *str) { | |
66 | + ostringstream s; | |
67 | + s << "Unterminated string constant: " << str; | |
68 | + OutputError(loc, s.str()); | |
69 | +} | |
70 | + | |
71 | +void ReportError::UnrecogChar(yyltype *loc, char ch) { | |
72 | + ostringstream s; | |
73 | + s << "Unrecognized char: '" << ch << "'"; | |
74 | + OutputError(loc, s.str()); | |
75 | +} | |
76 | + | |
77 | +void ReportError::DeclConflict(Decl *decl, Decl *prevDecl) { | |
78 | + ostringstream s; | |
79 | + s << "Declaration of '" << decl << "' here conflicts with declaration on line " | |
80 | + << prevDecl->GetLocation()->first_line; | |
81 | + OutputError(decl->GetLocation(), s.str()); | |
82 | +} | |
83 | + | |
84 | +void ReportError::InvalidInitialization(Identifier *id, Type *lType, Type *rType) { | |
85 | + ostringstream s; | |
86 | + s << "Wrong initialization of identifier '" << id << "': idType '" | |
87 | + << lType << "' exprType '" << rType << "'" ; | |
88 | + OutputError(id->GetLocation(), s.str()); | |
89 | +} | |
90 | + | |
91 | +void ReportError::IdentifierNotDeclared(Identifier *ident, reasonT whyNeeded) { | |
92 | + ostringstream s; | |
93 | + static const char *names[] = {"type", "variable", "function"}; | |
94 | + Assert(whyNeeded >= 0 && whyNeeded <= sizeof(names)/sizeof(names[0])); | |
95 | + s << "No declaration found for "<< names[whyNeeded] << " '" << ident << "'"; | |
96 | + OutputError(ident->GetLocation(), s.str()); | |
97 | +} | |
98 | + | |
99 | +void ReportError::ExtraFormals(Identifier *id, int expCount, int actualCount) { | |
100 | + ostringstream s; | |
101 | + s << "Extra arguments given to function '" << id << "': expected " | |
102 | + << expCount << ", given " << actualCount ; | |
103 | + OutputError(id->GetLocation(), s.str()); | |
104 | +} | |
105 | + | |
106 | +void ReportError::LessFormals(Identifier *id, int expCount, int actualCount) { | |
107 | + ostringstream s; | |
108 | + s << "Less arguments given to function '" << id << "': expected " | |
109 | + << expCount << ", given " << actualCount ; | |
110 | + OutputError(id->GetLocation(), s.str()); | |
111 | +} | |
112 | + | |
113 | +void ReportError::FormalsTypeMismatch(Identifier *id, int pos, Type *expType, Type *actualType) | |
114 | +{ | |
115 | + ostringstream s; | |
116 | + s << "Formal type mismatch in function '" << id << "' at pos " << pos | |
117 | + << ": expected '" << expType << "', given '" << actualType <<"'"; | |
118 | + OutputError(id->GetLocation(), s.str()); | |
119 | +} | |
120 | + | |
121 | +void ReportError::NotAFunction(Identifier *id) { | |
122 | + ostringstream s; | |
123 | + s << "'" << id << "' is not a function."; | |
124 | + OutputError(id->GetLocation(), s.str()); | |
125 | +} | |
126 | + | |
127 | +void ReportError::NotAnArray(Identifier *id) { | |
128 | + ostringstream s; | |
129 | + s << "'" << id << "' is not an array."; | |
130 | + OutputError(id->GetLocation(), s.str()); | |
131 | +} | |
132 | + | |
133 | +void ReportError::IncompatibleOperands(Operator *op, Type *lhs, Type *rhs) { | |
134 | + ostringstream s; | |
135 | + s << "Incompatible operands: " << lhs << " " << op << " " << rhs; | |
136 | + OutputError(op->GetLocation(), s.str()); | |
137 | +} | |
138 | + | |
139 | +void ReportError::IncompatibleOperand(Operator *op, Type *rhs) { | |
140 | + ostringstream s; | |
141 | + s << "Incompatible operand: " << op << " " << rhs; | |
142 | + OutputError(op->GetLocation(), s.str()); | |
143 | +} | |
144 | + | |
145 | +void ReportError::ReturnMismatch(ReturnStmt *rStmt, Type *given, Type *expected) { | |
146 | + ostringstream s; | |
147 | + s << "Incompatible return: " << given << " given, " << expected << " expected"; | |
148 | + OutputError(rStmt->GetLocation(), s.str()); | |
149 | +} | |
150 | + | |
151 | +void ReportError::ReturnMissing(FnDecl *fnDecl) { | |
152 | + ostringstream s; | |
153 | + s << "Declaration of '" << fnDecl << "' on line " | |
154 | + << fnDecl->GetLocation()->first_line | |
155 | + << " doesn't have a return"; | |
156 | + OutputError(fnDecl->GetLocation(), s.str()); | |
157 | +} | |
158 | + | |
159 | +void ReportError::InaccessibleSwizzle(Identifier *field, Expr *base) { | |
160 | + ostringstream s; | |
161 | + s << base << " non-vector type can't have swizzle '" << field <<"'"; | |
162 | + OutputError(field->GetLocation(), s.str()); | |
163 | +} | |
164 | + | |
165 | +void ReportError::InvalidSwizzle(Identifier *field, Expr *base) { | |
166 | + ostringstream s; | |
167 | + s << base << " swizzle '" << field <<"' is not proper subset of [xyzw]"; | |
168 | + OutputError(field->GetLocation(), s.str()); | |
169 | +} | |
170 | + | |
171 | +void ReportError::SwizzleOutOfBound(Identifier *field, Expr *base) { | |
172 | + ostringstream s; | |
173 | + s << base << " swizzle '" << field <<"' exceeds its vector component"; | |
174 | + OutputError(field->GetLocation(), s.str()); | |
175 | +} | |
176 | + | |
177 | +void ReportError::OversizedVector(Identifier *field, Expr *base) { | |
178 | + ostringstream s; | |
179 | + s << base << " swizzle '" << field <<"' generates a vector longer than vec4"; | |
180 | + OutputError(field->GetLocation(), s.str()); | |
181 | +} | |
182 | + | |
183 | +void ReportError::TestNotBoolean(Expr *expr) { | |
184 | + OutputError(expr->GetLocation(), "Test expression must have boolean type"); | |
185 | +} | |
186 | + | |
187 | +void ReportError::BreakOutsideLoop(BreakStmt *bStmt) { | |
188 | + OutputError(bStmt->GetLocation(), "break is only allowed inside a loop"); | |
189 | +} | |
190 | + | |
191 | +void ReportError::ContinueOutsideLoop(ContinueStmt *cStmt) { | |
192 | + OutputError(cStmt->GetLocation(), "continue is only allowed inside a loop"); | |
193 | +} | |
194 | + | |
195 | +/** | |
196 | + * Function: yyerror() | |
197 | + * ------------------- | |
198 | + * Standard error-reporting function expected by yacc. Our version merely | |
199 | + * just calls into the error reporter above, passing the location of | |
200 | + * the last token read. If you want to suppress the ordinary "parse error" | |
201 | + * message from yacc, you can implement yyerror to do nothing and | |
202 | + * then call ReportError::Formatted yourself with a more descriptive | |
203 | + * message. | |
204 | + */ | |
205 | + | |
206 | +void yyerror(const char *msg) { | |
207 | + ReportError::Formatted(&yylloc, "%s", msg); | |
208 | +} |
errors.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,114 @@ |
1 | +/** | |
2 | + * File: errors.h | |
3 | + * -------------- | |
4 | + * This file defines an error-reporting class with a set of already | |
5 | + * implemented static methods for reporting the standard Decaf errors. | |
6 | + * You should report all errors via this class so that your error | |
7 | + * messages will have the same wording/spelling as ours and thus | |
8 | + * diff can easily compare the two. If needed, you can add new | |
9 | + * methods if you have some fancy error-reporting, but for the most | |
10 | + * part, you will just use the class as given. | |
11 | + */ | |
12 | + | |
13 | +#ifndef _errors_h_ | |
14 | +#define _errors_h_ | |
15 | + | |
16 | +#include <string> | |
17 | +#include "location.h" | |
18 | +#include "ast_decl.h" | |
19 | + | |
20 | +using namespace std; | |
21 | + | |
22 | +/** | |
23 | + * General notes on using this class | |
24 | + * ---------------------------------- | |
25 | + * Each of the methods in thie class matches one of the standard Decaf | |
26 | + * errors and reports a specific problem such as an unterminated string, | |
27 | + * type mismatch, declaration conflict, etc. You will call these methods | |
28 | + * to report problems encountered during the analysis phases. All methods | |
29 | + * on this class are static, thus you can invoke methods directly via | |
30 | + * the class name, e.g. | |
31 | + * | |
32 | + * if (missingEnd) { | |
33 | + * ReportError::UntermString(&yylloc, str); | |
34 | + * } | |
35 | + * | |
36 | + * For some methods, the first argument is the pointer to the location | |
37 | + * structure that identifies where the problem is (usually this is the | |
38 | + * location of the offending token). You can pass NULL for the argument | |
39 | + * if there is no appropriate position to point out. For other methods, | |
40 | + * location is accessed by messaging the node in error which is passed | |
41 | + * as an argument. You cannot pass NULL for these arguments. | |
42 | + */ | |
43 | + | |
44 | +class Type; | |
45 | +class Identifier; | |
46 | +class Expr; | |
47 | +class BreakStmt; | |
48 | +class ContinueStmt; | |
49 | +class ReturnStmt; | |
50 | +class Decl; | |
51 | +class Operator; | |
52 | + | |
53 | +typedef enum { | |
54 | + LookingForType, | |
55 | + LookingForVariable, | |
56 | + LookingForFunction | |
57 | +} reasonT; | |
58 | + | |
59 | +class ReportError { | |
60 | + public: | |
61 | + | |
62 | + // Errors used by scanner | |
63 | + static void UntermComment(); | |
64 | + static void LongIdentifier(yyltype *loc, const char *ident); | |
65 | + static void UntermString(yyltype *loc, const char *str); | |
66 | + static void UnrecogChar(yyltype *loc, char ch); | |
67 | + | |
68 | + // Errors used by semantic analyzer for declarations | |
69 | + static void DeclConflict(Decl *newDecl, Decl *prevDecl); | |
70 | + static void InvalidInitialization(Identifier *id, Type *lType, Type *rType); | |
71 | + | |
72 | + | |
73 | + // Errors used by semantic analyzer for identifiers | |
74 | + static void IdentifierNotDeclared(Identifier *ident, reasonT whyNeeded); | |
75 | + | |
76 | + // Errors used by semantic analyzer for arrays | |
77 | + static void NotAnArray(Identifier *id); | |
78 | + | |
79 | + // Errors used by semantic analyzer for expressions | |
80 | + static void IncompatibleOperand(Operator *op, Type *rhs); // unary | |
81 | + static void IncompatibleOperands(Operator *op, Type *lhs, Type *rhs); // binary | |
82 | + | |
83 | + // Errors used by semantic analyzer for function calls | |
84 | + static void ExtraFormals(Identifier *id, int expCount, int actualCount); | |
85 | + static void LessFormals(Identifier *id, int expCount, int actualCount); | |
86 | + static void FormalsTypeMismatch(Identifier *id, int pos, Type *expType, Type *actualType); | |
87 | + static void NotAFunction(Identifier *id); | |
88 | + | |
89 | + // Errors used by semantic analyzer for vector access | |
90 | + static void InaccessibleSwizzle(Identifier *swizzle, Expr *base); | |
91 | + static void InvalidSwizzle(Identifier *swizzle, Expr *base); | |
92 | + static void SwizzleOutOfBound(Identifier *swizzle, Expr *base); | |
93 | + static void OversizedVector(Identifier *swizzle, Expr *base); | |
94 | + | |
95 | + // Errors used by semantic analyzer for control structures | |
96 | + static void TestNotBoolean(Expr *testExpr); | |
97 | + static void ReturnMismatch(ReturnStmt *rStmt, Type *given, Type *expected); | |
98 | + static void ReturnMissing(FnDecl *fnDecl); | |
99 | + static void BreakOutsideLoop(BreakStmt *bStmt); | |
100 | + static void ContinueOutsideLoop(ContinueStmt *cStmt); | |
101 | + | |
102 | + // Generic method to report a printf-style error message | |
103 | + static void Formatted(yyltype *loc, const char *format, ...); | |
104 | + | |
105 | + | |
106 | + // Returns number of error messages printed | |
107 | + static int NumErrors() { return numErrors; } | |
108 | + | |
109 | + private: | |
110 | + static void UnderlineErrorInLine(const char *line, yyltype *pos); | |
111 | + static void OutputError(yyltype *loc, string msg); | |
112 | + static int numErrors; | |
113 | +}; | |
114 | +#endif |
irgen.cc
View file @
c30bbd1
... | ... | @@ -0,0 +1,64 @@ |
1 | +/* irgen.cc - LLVM IR generator | |
2 | + * | |
3 | + * You can implement any LLVM related functions here. | |
4 | + */ | |
5 | + | |
6 | +#include "irgen.h" | |
7 | + | |
8 | +IRGenerator::IRGenerator() : | |
9 | + context(NULL), | |
10 | + module(NULL), | |
11 | + currentFunc(NULL), | |
12 | + currentBB(NULL) | |
13 | +{ | |
14 | +} | |
15 | + | |
16 | +IRGenerator::~IRGenerator() { | |
17 | +} | |
18 | + | |
19 | +llvm::Module *IRGenerator::GetOrCreateModule(const char *moduleID) | |
20 | +{ | |
21 | + if ( module == NULL ) { | |
22 | + context = new llvm::LLVMContext(); | |
23 | + module = new llvm::Module(moduleID, *context); | |
24 | + module->setTargetTriple(TargetTriple); | |
25 | + module->setDataLayout(TargetLayout); | |
26 | + } | |
27 | + return module; | |
28 | +} | |
29 | + | |
30 | +void IRGenerator::SetFunction(llvm::Function *func) { | |
31 | + currentFunc = func; | |
32 | +} | |
33 | + | |
34 | +llvm::Function *IRGenerator::GetFunction() const { | |
35 | + return currentFunc; | |
36 | +} | |
37 | + | |
38 | +void IRGenerator::SetBasicBlock(llvm::BasicBlock *bb) { | |
39 | + currentBB = bb; | |
40 | +} | |
41 | + | |
42 | +llvm::BasicBlock *IRGenerator::GetBasicBlock() const { | |
43 | + return currentBB; | |
44 | +} | |
45 | + | |
46 | +llvm::Type *IRGenerator::GetIntType() const { | |
47 | + llvm::Type *ty = llvm::Type::getInt32Ty(*context); | |
48 | + return ty; | |
49 | +} | |
50 | + | |
51 | +llvm::Type *IRGenerator::GetBoolType() const { | |
52 | + llvm::Type *ty = llvm::Type::getInt1Ty(*context); | |
53 | + return ty; | |
54 | +} | |
55 | + | |
56 | +llvm::Type *IRGenerator::GetFloatType() const { | |
57 | + llvm::Type *ty = llvm::Type::getFloatTy(*context); | |
58 | + return ty; | |
59 | +} | |
60 | + | |
61 | +const char *IRGenerator::TargetLayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"; | |
62 | + | |
63 | +const char *IRGenerator::TargetTriple = "x86_64-redhat-linux-gnu"; | |
64 | + |
irgen.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,52 @@ |
1 | +/** | |
2 | + * File: irgen.h | |
3 | + * ----------- | |
4 | + * This file defines a class for LLVM IR Generation. | |
5 | + * | |
6 | + * All LLVM instruction related functions or utilities can be implemented | |
7 | + * here. You'll need to customize this class heavily to provide any helpers | |
8 | + * or untility as you need. | |
9 | + */ | |
10 | + | |
11 | +#ifndef _H_IRGen | |
12 | +#define _H_IRGen | |
13 | + | |
14 | +// LLVM headers | |
15 | +#include "llvm/IR/Module.h" | |
16 | +#include "llvm/IR/LLVMContext.h" | |
17 | +#include "llvm/IR/Instructions.h" | |
18 | +#include "llvm/IR/Constants.h" | |
19 | + | |
20 | +class IRGenerator { | |
21 | + public: | |
22 | + IRGenerator(); | |
23 | + ~IRGenerator(); | |
24 | + | |
25 | + llvm::Module *GetOrCreateModule(const char *moduleID); | |
26 | + llvm::LLVMContext *GetContext() const { return context; } | |
27 | + | |
28 | + // Add your helper functions here | |
29 | + llvm::Function *GetFunction() const; | |
30 | + void SetFunction(llvm::Function *func); | |
31 | + | |
32 | + llvm::BasicBlock *GetBasicBlock() const; | |
33 | + void SetBasicBlock(llvm::BasicBlock *bb); | |
34 | + | |
35 | + llvm::Type *GetIntType() const; | |
36 | + llvm::Type *GetBoolType() const; | |
37 | + llvm::Type *GetFloatType() const; | |
38 | + | |
39 | + private: | |
40 | + llvm::LLVMContext *context; | |
41 | + llvm::Module *module; | |
42 | + | |
43 | + // track which function or basic block is active | |
44 | + llvm::Function *currentFunc; | |
45 | + llvm::BasicBlock *currentBB; | |
46 | + | |
47 | + static const char *TargetTriple; | |
48 | + static const char *TargetLayout; | |
49 | +}; | |
50 | + | |
51 | +#endif | |
52 | + |
list.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,88 @@ |
1 | +/** | |
2 | + * File: list.h | |
3 | + * ------------ | |
4 | + * Simple list class for storing a linear collection of elements. It | |
5 | + * supports operations similar in name to the CS107 CVector -- nth, insert, | |
6 | + * append, remove, etc. This class is nothing more than a very thin | |
7 | + * cover of a STL deque, with some added range-checking. Given not everyone | |
8 | + * is familiar with the C++ templates, this class provides a more familiar | |
9 | + * interface. | |
10 | + * | |
11 | + * It can handle elements of any type, the typename for a List includes the | |
12 | + * element type in angle brackets, e.g. to store elements of type double, | |
13 | + * you would use the type name List<double>, to store elements of type | |
14 | + * Decl *, it woud be List<Decl*> and so on. | |
15 | + * | |
16 | + * Here is some sample code illustrating the usage of a List of integers | |
17 | + * | |
18 | + * int Sum(List<int> *list) { | |
19 | + * int sum = 0; | |
20 | + * for (int i = 0; i < list->NumElements(); i++) { | |
21 | + * int val = list->Nth(i); | |
22 | + * sum += val; | |
23 | + * } | |
24 | + * return sum; | |
25 | + * } | |
26 | + */ | |
27 | + | |
28 | +#ifndef _H_list | |
29 | +#define _H_list | |
30 | + | |
31 | +#include <deque> | |
32 | +#include "utility.h" // for Assert() | |
33 | +using namespace std; | |
34 | + | |
35 | +class Node; | |
36 | + | |
37 | +template<class Element> class List { | |
38 | + | |
39 | + private: | |
40 | + deque<Element> elems; | |
41 | + | |
42 | + public: | |
43 | + // Create a new empty list | |
44 | + List() {} | |
45 | + | |
46 | + // Returns count of elements currently in list | |
47 | + int NumElements() const | |
48 | + { return elems.size(); } | |
49 | + | |
50 | + // Returns element at index in list. Indexing is 0-based. | |
51 | + // Raises an assert if index is out of range. | |
52 | + Element Nth(int index) const | |
53 | + { Assert(index >= 0 && index < NumElements()); | |
54 | + return elems[index]; } | |
55 | + | |
56 | + // Inserts element at index, shuffling over others | |
57 | + // Raises assert if index out of range | |
58 | + void InsertAt(const Element &elem, int index) | |
59 | + { Assert(index >= 0 && index <= NumElements()); | |
60 | + elems.insert(elems.begin() + index, elem); } | |
61 | + | |
62 | + // Adds element to list end | |
63 | + void Append(const Element &elem) | |
64 | + { elems.push_back(elem); } | |
65 | + | |
66 | + // Removes element at index, shuffling down others | |
67 | + // Raises assert if index out of range | |
68 | + void RemoveAt(int index) | |
69 | + { Assert(index >= 0 && index < NumElements()); | |
70 | + elems.erase(elems.begin() + index); } | |
71 | + | |
72 | + // These are some specific methods useful for lists of ast nodes | |
73 | + // They will only work on lists of elements that respond to the | |
74 | + // messages, but since C++ only instantiates the template if you use | |
75 | + // you can still have Lists of ints, chars*, as long as you | |
76 | + // don't try to SetParentAll on that list. | |
77 | + void SetParentAll(Node *p) | |
78 | + { for (int i = 0; i < NumElements(); i++) | |
79 | + Nth(i)->SetParent(p); } | |
80 | + void PrintAll(int indentLevel, const char *label = NULL) | |
81 | + { for (int i = 0; i < NumElements(); i++) | |
82 | + Nth(i)->Print(indentLevel, label); } | |
83 | + | |
84 | + | |
85 | +}; | |
86 | + | |
87 | +#endif | |
88 | + |
location.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,59 @@ |
1 | +/* File: location.h | |
2 | + * ---------------- | |
3 | + * This file just contains features relative to the location structure | |
4 | + * used to record the lexical position of a token or symbol. This file | |
5 | + * establishes the cmoon definition for the yyltype structure, the global | |
6 | + * variable yylloc, and a utility function to join locations you might | |
7 | + * find handy at times. | |
8 | + */ | |
9 | + | |
10 | +#ifndef YYLTYPE | |
11 | + | |
12 | +/* Typedef: yyltype | |
13 | + * ---------------- | |
14 | + * Defines the struct type that is used by the scanner to store | |
15 | + * position information about each lexeme scanned. | |
16 | + */ | |
17 | +typedef struct yyltype | |
18 | +{ | |
19 | + int timestamp; // you can ignore this field | |
20 | + int first_line, first_column; | |
21 | + int last_line, last_column; | |
22 | + char *text; // you can also ignore this field | |
23 | +} yyltype; | |
24 | + | |
25 | +#define YYLTYPE yyltype | |
26 | + | |
27 | + | |
28 | +/* Global variable: yylloc | |
29 | + * ------------------------ | |
30 | + * The global variable holding the position information about the | |
31 | + * lexeme just scanned. | |
32 | + */ | |
33 | +extern struct yyltype yylloc; | |
34 | + | |
35 | + | |
36 | +/* Function: Join | |
37 | + * -------------- | |
38 | + * Takes two locations and returns a new location which represents | |
39 | + * the span from first to last, inclusive. | |
40 | + */ | |
41 | +inline yyltype Join(yyltype first, yyltype last) | |
42 | +{ | |
43 | + yyltype combined; | |
44 | + combined.first_column = first.first_column; | |
45 | + combined.first_line = first.first_line; | |
46 | + combined.last_column = last.last_column; | |
47 | + combined.last_line = last.last_line; | |
48 | + return combined; | |
49 | +} | |
50 | + | |
51 | +/* Same as above, except operates on pointers as a convenience */ | |
52 | +inline yyltype Join(yyltype *firstPtr, yyltype *lastPtr) | |
53 | +{ | |
54 | + return Join(*firstPtr, *lastPtr); | |
55 | +} | |
56 | + | |
57 | + | |
58 | +#endif | |
59 | + |
main.cc
View file @
c30bbd1
... | ... | @@ -0,0 +1,30 @@ |
1 | +/* File: main.cc | |
2 | + * ------------- | |
3 | + * This file defines the main() routine for the program and not much else. | |
4 | + * You should not need to modify this file. | |
5 | + */ | |
6 | + | |
7 | +#include <string.h> | |
8 | +#include <stdio.h> | |
9 | +#include "utility.h" | |
10 | +#include "errors.h" | |
11 | +#include "parser.h" | |
12 | + | |
13 | + | |
14 | +/* Function: main() | |
15 | + * ---------------- | |
16 | + * Entry point to the entire program. We parse the command line and turn | |
17 | + * on any debugging flags requested by the user when invoking the program. | |
18 | + * InitScanner() is used to set up the scanner. | |
19 | + * InitParser() is used to set up the parser. The call to yyparse() will | |
20 | + * attempt to parse a complete program from the input. | |
21 | + */ | |
22 | +int main(int argc, char *argv[]) | |
23 | +{ | |
24 | + ParseCommandLine(argc, argv); | |
25 | + InitScanner(); | |
26 | + InitParser(); | |
27 | + yyparse(); | |
28 | + return (ReportError::NumErrors() == 0? 0 : -1); | |
29 | +} | |
30 | + |
parser.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,38 @@ |
1 | +/* File: parser.h | |
2 | + * -------------- | |
3 | + * This file provides constants and type definitions that will | |
4 | + * are used and/or exported by the yacc-generated parser. | |
5 | + */ | |
6 | + | |
7 | +#ifndef _H_parser | |
8 | +#define _H_parser | |
9 | + | |
10 | + // here we need to include things needed for the yylval union | |
11 | + // (types, classes, constants, etc.) | |
12 | + | |
13 | +#include "scanner.h" // for MaxIdentLen | |
14 | +#include "list.h" // because we use all these types | |
15 | +#include "ast.h" // in the union, we need their declarations | |
16 | +#include "ast_type.h" | |
17 | +#include "ast_decl.h" | |
18 | +#include "ast_expr.h" | |
19 | +#include "ast_stmt.h" | |
20 | + | |
21 | + | |
22 | +// Next, we want to get the exported defines for the token codes and | |
23 | +// typedef for YYSTYPE and exported global variable yylval. These | |
24 | +// definitions are generated and written to the y.tab.h header file. But | |
25 | +// because that header does not have any protection against being | |
26 | +// re-included and those definitions are also present in the y.tab.c, | |
27 | +// we can get into trouble if we don't take precaution to not include if | |
28 | +// we are compiling y.tab.c, which we use the YYBISON symbol for. | |
29 | +// Managing C headers can be such a mess! | |
30 | + | |
31 | +#ifndef YYBISON | |
32 | +#include "y.tab.h" | |
33 | +#endif | |
34 | + | |
35 | +int yyparse(); // Defined in the generated y.tab.c file | |
36 | +void InitParser(); // Defined in parser.y | |
37 | + | |
38 | +#endif |
parser.y
View file @
c30bbd1
... | ... | @@ -0,0 +1,504 @@ |
1 | +/* File: parser.y | |
2 | + * -------------- | |
3 | + * Bison input file to generate the parser for the compiler. | |
4 | + * | |
5 | + * pp2: your job is to write a parser that will construct the parse tree | |
6 | + * and if no parse errors were found, print it. The parser should | |
7 | + * accept the language as described in specification, and as augmented | |
8 | + * in the pp2 handout. | |
9 | + */ | |
10 | + | |
11 | +%{ | |
12 | + | |
13 | +/* Just like lex, the text within this first region delimited by %{ and %} | |
14 | + * is assumed to be C/C++ code and will be copied verbatim to the y.tab.c | |
15 | + * file ahead of the definitions of the yyparse() function. Add other header | |
16 | + * file inclusions or C++ variable declarations/prototypes that are needed | |
17 | + * by your code here. | |
18 | + */ | |
19 | +#include "scanner.h" // for yylex | |
20 | +#include "parser.h" | |
21 | +#include "errors.h" | |
22 | + | |
23 | +void yyerror(const char *msg); // standard error-handling routine | |
24 | + | |
25 | +%} | |
26 | + | |
27 | +/* The section before the first %% is the Definitions section of the yacc | |
28 | + * input file. Here is where you declare tokens and types, add precedence | |
29 | + * and associativity options, and so on. | |
30 | + */ | |
31 | + | |
32 | +/* yylval | |
33 | + * ------ | |
34 | + * Here we define the type of the yylval global variable that is used by | |
35 | + * the scanner to store attibute information about the token just scanned | |
36 | + * and thus communicate that information to the parser. | |
37 | + * | |
38 | + * pp2: You will need to add new fields to this union as you add different | |
39 | + * attributes to your non-terminal symbols. | |
40 | + */ | |
41 | +%union { | |
42 | + int integerConstant; | |
43 | + bool boolConstant; | |
44 | + double floatConstant; | |
45 | + char identifier[MaxIdentLen+1]; // +1 for terminating null | |
46 | + Decl *decl; | |
47 | + FnDecl *funcDecl; | |
48 | + List<Decl*> *declList; | |
49 | + Type *typeDecl; | |
50 | + TypeQualifier *typeQualifier; | |
51 | + Expr *expression; | |
52 | + VarDecl *varDecl; | |
53 | + List<VarDecl *> *varDeclList; | |
54 | + List<Stmt*> *stmtList; | |
55 | + Stmt *stmt; | |
56 | + Operator *ops; | |
57 | + Identifier *funcId; | |
58 | + List<Expr*> *argList; | |
59 | +} | |
60 | + | |
61 | + | |
62 | +/* Tokens | |
63 | + * ------ | |
64 | + * Here we tell yacc about all the token types that we are using. | |
65 | + * Bison will assign unique numbers to these and export the #define | |
66 | + * in the generated y.tab.h header file. | |
67 | + */ | |
68 | +%token T_Void T_Bool T_Int T_Float T_Uint | |
69 | +%token T_Bvec2 T_Bvec3 T_Bvec4 T_Ivec2 T_Ivec3 T_Ivec4 | |
70 | +%token T_Uvec2 T_Uvec3 T_Uvec4 T_Vec2 T_Vec3 T_Vec4 | |
71 | +%token T_Mat2 T_Mat3 T_Mat4 | |
72 | +%token T_While T_For T_If T_Else T_Return T_Break T_Continue T_Do | |
73 | +%token T_Switch T_Case T_Default | |
74 | +%token T_In T_Out T_Const T_Uniform | |
75 | +%token T_LeftParen T_RightParen T_LeftBracket T_RightBracket T_LeftBrace T_RightBrace | |
76 | +%token T_Dot T_Comma T_Colon T_Semicolon T_Question | |
77 | + | |
78 | +%token <identifier> T_LessEqual T_GreaterEqual T_EQ T_NE | |
79 | +%token <identifier> T_And T_Or | |
80 | +%token <identifier> T_Plus T_Star | |
81 | +%token <identifier> T_MulAssign T_DivAssign T_AddAssign T_SubAssign T_Equal | |
82 | +%token <identifier> T_LeftAngle T_RightAngle T_Dash T_Slash | |
83 | +%token <identifier> T_Inc T_Dec | |
84 | +%token <identifier> T_Identifier | |
85 | +%token <integerConstant> T_IntConstant | |
86 | +%token <floatConstant> T_FloatConstant | |
87 | +%token <boolConstant> T_BoolConstant | |
88 | +%token <identifier> T_FieldSelection | |
89 | + | |
90 | +%nonassoc LOWEST | |
91 | +%nonassoc LOWER_THAN_ELSE | |
92 | +%nonassoc T_Else | |
93 | +%right T_Equal T_MulAssign T_DivAssign T_AddAssign T_SubAssign | |
94 | +%right T_Question T_Colon | |
95 | +%left T_EQ T_NE T_LeftAngle T_RightAngle T_And T_Or T_GreaterEqual | |
96 | +%left T_Plus T_Dash T_Star T_Slash | |
97 | + | |
98 | +/* Non-terminal types | |
99 | + * ------------------ | |
100 | + * In order for yacc to assign/access the correct field of $$, $1, we | |
101 | + * must to declare which field is appropriate for the non-terminal. | |
102 | + * As an example, this first type declaration establishes that the DeclList | |
103 | + * non-terminal uses the field named "declList" in the yylval union. This | |
104 | + * means that when we are setting $$ for a reduction for DeclList ore reading | |
105 | + * $n which corresponds to a DeclList nonterminal we are accessing the field | |
106 | + * of the union named "declList" which is of type List<Decl*>. | |
107 | + * pp2: You'll need to add many of these of your own. | |
108 | + */ | |
109 | +%type <declList> DeclList | |
110 | +%type <decl> Decl | |
111 | +%type <decl> Declaration | |
112 | +%type <funcDecl> FuncDecl | |
113 | +%type <typeDecl> TypeDecl | |
114 | +%type <typeQualifier> TypeQualify | |
115 | +%type <expression> PrimaryExpr PostfixExpr UnaryExpr MultiExpr AdditionExpr RelationExpr Initializer FunctionCallExpr FunctionCallHeaderWithParameters FunctionCallHeaderNoParameters | |
116 | +%type <expression> EqualityExpr LogicAndExpr LogicOrExpr Expression | |
117 | + /*%type <floatConstant> Initializer*/ | |
118 | +%type <varDecl> SingleDecl | |
119 | +%type <varDeclList> ParameterList | |
120 | +%type <stmt> Statement | |
121 | +%type <stmtList> StatementList | |
122 | +%type <stmt> SingleStatement SelectionStmt SwitchStmt CaseStmt JumpStmt WhileStmt ForStmt | |
123 | +%type <stmt> CompoundStatement | |
124 | +%type <ops> AssignOp | |
125 | +%type <funcId> FunctionIdentifier | |
126 | +%type <argList> ArgumentList | |
127 | + | |
128 | +%% | |
129 | +/* Rules | |
130 | + * ----- | |
131 | + * All productions and actions should be placed between the start and stop | |
132 | + * %% markers which delimit the Rules section. | |
133 | + | |
134 | + */ | |
135 | +Program : DeclList { | |
136 | + @1; | |
137 | + /* pp2: The @1 is needed to convince | |
138 | + * yacc to set up yylloc. You can remove | |
139 | + * it once you have other uses of @n*/ | |
140 | + Program *program = new Program($1); | |
141 | + // if no errors, advance to next phase | |
142 | + if (ReportError::NumErrors() == 0) { | |
143 | + if ( IsDebugOn("dumpAST") ) { | |
144 | + program->Print(0); | |
145 | + } | |
146 | + program->Emit(); | |
147 | + } | |
148 | + } | |
149 | + ; | |
150 | + | |
151 | +DeclList : DeclList Decl { ($$=$1)->Append($2); } | |
152 | + | Decl { ($$ = new List<Decl*>)->Append($1); } | |
153 | + ; | |
154 | + | |
155 | +/* combine external_declaration and function_definition into a single rule | |
156 | + * external_declaration: | |
157 | + * function_definition | |
158 | + * declaration | |
159 | + * function_definition: | |
160 | + * function_prototype compound_statement | |
161 | + */ | |
162 | + | |
163 | +Decl : Declaration { $$ = $1; } | |
164 | + | FuncDecl CompoundStatement { $1->SetFunctionBody($2); $$ = $1; } | |
165 | + ; | |
166 | + | |
167 | +/* combine declaration and init_decl_list into a single rule | |
168 | + * declaration: | |
169 | + * function_prototype SEMICOLON | |
170 | + * init_decl_list SEMICOLON | |
171 | + * init_decl_list: | |
172 | + * single_declaration | |
173 | + */ | |
174 | + | |
175 | +Declaration : FuncDecl T_Semicolon { $$ = $1; } | |
176 | + | SingleDecl T_Semicolon { $$ = $1; } | |
177 | + ; | |
178 | + | |
179 | +FuncDecl : TypeDecl T_Identifier T_LeftParen T_RightParen | |
180 | + { | |
181 | + Identifier *id = new Identifier(yylloc, (const char *)$2); | |
182 | + List<VarDecl *> *formals = new List<VarDecl *>; | |
183 | + $$ = new FnDecl(id, $1, formals); | |
184 | + } | |
185 | + | TypeDecl T_Identifier T_LeftParen ParameterList T_RightParen | |
186 | + { | |
187 | + Identifier *id = new Identifier(yylloc, (const char *)$2); | |
188 | + $$ = new FnDecl(id, $1, $4); | |
189 | + } | |
190 | + ; | |
191 | + | |
192 | +ParameterList : SingleDecl { ($$ = new List<VarDecl *>)->Append($1); } | |
193 | + | ParameterList T_Comma SingleDecl { ($$ = $1)->Append($3); } | |
194 | + ; | |
195 | + | |
196 | +SingleDecl : TypeDecl T_Identifier | |
197 | + { | |
198 | + Identifier *id = new Identifier(yylloc, (const char *)$2); | |
199 | + $$ = new VarDecl(id, $1); | |
200 | + } | |
201 | + | TypeQualify TypeDecl T_Identifier | |
202 | + { | |
203 | + Identifier *id = new Identifier(yylloc, (const char *)$3); | |
204 | + $$ = new VarDecl(id, $2, $1); | |
205 | + } | |
206 | + | TypeDecl T_Identifier T_Equal Initializer | |
207 | + { | |
208 | + // incomplete: drop the initializer here | |
209 | + Identifier *id = new Identifier(yylloc, (const char *)$2); | |
210 | + $$ = new VarDecl(id, $1, $4); | |
211 | + } | |
212 | + | TypeQualify TypeDecl T_Identifier T_Equal Initializer | |
213 | + { | |
214 | + Identifier *id = new Identifier(yylloc, (const char *)$3); | |
215 | + $$ = new VarDecl(id, $2, $1, $5); | |
216 | + } | |
217 | + | TypeDecl T_Identifier T_LeftBracket T_IntConstant T_RightBracket | |
218 | + { | |
219 | + Identifier *id = new Identifier(@2, (const char *)$2); | |
220 | + $$ = new VarDecl(id, new ArrayType(@1, $1, $4)); | |
221 | + } | |
222 | + | TypeQualify TypeDecl T_Identifier T_LeftBracket T_IntConstant T_RightBracket | |
223 | + { | |
224 | + Identifier *id = new Identifier(@3, $3); | |
225 | + $$ = new VarDecl(id, new ArrayType(@2, $2, $5), $1); | |
226 | + } | |
227 | + | |
228 | + ; | |
229 | + | |
230 | +Initializer : Expression { $$ = $1; } | |
231 | + ; | |
232 | + | |
233 | +TypeQualify : T_In {$$ = TypeQualifier::inTypeQualifier;} | |
234 | + | T_Out {$$ = TypeQualifier::outTypeQualifier;} | |
235 | + | T_Const {$$ = TypeQualifier::constTypeQualifier;} | |
236 | + | T_Uniform {$$ = TypeQualifier::uniformTypeQualifier;} | |
237 | + ; | |
238 | + | |
239 | +TypeDecl : T_Int { $$ = Type::intType; } | |
240 | + | T_Void { $$ = Type::voidType; } | |
241 | + | T_Float { $$ = Type::floatType; } | |
242 | + | T_Bool { $$ = Type::boolType; } | |
243 | + | T_Vec2 { $$ = Type::vec2Type; } | |
244 | + | T_Vec3 { $$ = Type::vec3Type; } | |
245 | + | T_Vec4 { $$ = Type::vec4Type; } | |
246 | + | T_Mat2 { $$ = Type::mat2Type; } | |
247 | + | T_Mat3 { $$ = Type::mat3Type; } | |
248 | + | T_Mat4 { $$ = Type::mat4Type; } | |
249 | + ; | |
250 | + | |
251 | +CompoundStatement : T_LeftBrace T_RightBrace { $$ = new StmtBlock(new List<VarDecl*>, new List<Stmt *>); } | |
252 | + | T_LeftBrace StatementList T_RightBrace { $$ = new StmtBlock(new List<VarDecl*>, $2); } | |
253 | + ; | |
254 | + | |
255 | +StatementList : Statement { ($$ = new List<Stmt*>)->Append($1); } | |
256 | + | StatementList Statement { ($$ = $1)->Append($2); } | |
257 | + ; | |
258 | + | |
259 | +Statement : CompoundStatement { $$ = $1; } | |
260 | + | SingleStatement { $$ = $1; } | |
261 | + ; | |
262 | + | |
263 | +SingleStatement : T_Semicolon { $$ = new EmptyExpr(); } | |
264 | + | SingleDecl T_Semicolon | |
265 | + { | |
266 | + $$ = new DeclStmt($1); | |
267 | + } | |
268 | + | Expression T_Semicolon { $$ = $1; } | |
269 | + | SelectionStmt { $$ = $1; } | |
270 | + | SwitchStmt { $$ = $1; } | |
271 | + | CaseStmt { $$ = $1; } | |
272 | + | JumpStmt { $$ = $1; } | |
273 | + | WhileStmt { $$ = $1; } | |
274 | + | ForStmt { $$ = $1; } | |
275 | + ; | |
276 | + | |
277 | +SelectionStmt : T_If T_LeftParen Expression T_RightParen Statement T_Else Statement | |
278 | + { | |
279 | + $$ = new IfStmt($3, $5, $7); | |
280 | + } | |
281 | + | T_If T_LeftParen Expression T_RightParen Statement %prec LOWER_THAN_ELSE | |
282 | + { | |
283 | + $$ = new IfStmt($3, $5, NULL); | |
284 | + } | |
285 | + ; | |
286 | + | |
287 | +SwitchStmt : T_Switch T_LeftParen Expression T_RightParen T_LeftBrace StatementList T_RightBrace | |
288 | + { | |
289 | + $$ = new SwitchStmt($3, $6, NULL); | |
290 | + } | |
291 | + ; | |
292 | +CaseStmt : T_Case Expression T_Colon Statement { $$ = new Case($2, $4); } | |
293 | + | T_Default T_Colon Statement { $$ = new Default($3); } | |
294 | + ; | |
295 | + | |
296 | +JumpStmt : T_Break T_Semicolon { $$ = new BreakStmt(yylloc); } | |
297 | + | T_Continue T_Semicolon { $$ = new ContinueStmt(yylloc); } | |
298 | + | T_Return T_Semicolon { $$ = new ReturnStmt(yylloc); } | |
299 | + | T_Return Expression T_Semicolon { $$ = new ReturnStmt(yyloc, $2); } | |
300 | + ; | |
301 | + | |
302 | +WhileStmt : T_While T_LeftParen Expression T_RightParen Statement { $$ = new WhileStmt($3, $5); } | |
303 | + ; | |
304 | + | |
305 | +ForStmt : T_For T_LeftParen Expression T_Semicolon Expression T_Semicolon Expression T_RightParen Statement | |
306 | + { | |
307 | + $$ = new ForStmt($3, $5, $7, $9); | |
308 | + } | |
309 | + ; | |
310 | + | |
311 | +PrimaryExpr : T_Identifier { Identifier *id = new Identifier(yylloc, (const char*)$1); | |
312 | + $$ = new VarExpr(yyloc, id); | |
313 | + } | |
314 | + | T_IntConstant { $$ = new IntConstant(yylloc, $1); } | |
315 | + | T_FloatConstant { $$ = new FloatConstant(yylloc, $1); } | |
316 | + | T_BoolConstant { $$ = new BoolConstant(yylloc, $1); } | |
317 | + | T_LeftParen Expression T_RightParen { $$ = $2;} | |
318 | + ; | |
319 | + | |
320 | +FunctionCallExpr : FunctionCallHeaderWithParameters T_RightParen { $$ = $1; } | |
321 | + | FunctionCallHeaderNoParameters T_RightParen { $$ = $1; } | |
322 | + ; | |
323 | + | |
324 | +FunctionCallHeaderNoParameters : FunctionIdentifier T_LeftParen T_Void { $$ = new Call(@1, NULL, $1, new List<Expr*>); } | |
325 | + | FunctionIdentifier T_LeftParen { $$ = new Call(@1, NULL, $1, new List<Expr*>); } | |
326 | + ; | |
327 | + | |
328 | +FunctionCallHeaderWithParameters : FunctionIdentifier T_LeftParen ArgumentList { $$ = new Call(@1, NULL, $1, $3);} | |
329 | + ; | |
330 | + | |
331 | +ArgumentList : Expression { ($$ = new List<Expr*>)->Append($1);} | |
332 | + | ArgumentList T_Comma Expression { ($$ = $1)->Append($3);} | |
333 | + ; | |
334 | + | |
335 | +FunctionIdentifier : T_Identifier { $$ = new Identifier(@1, $1); } | |
336 | + ; | |
337 | + | |
338 | +PostfixExpr : PrimaryExpr { $$ = $1; } | |
339 | + | PostfixExpr T_LeftBracket Expression T_RightBracket { $$ = new ArrayAccess(@1, $1, $3); } | |
340 | + | FunctionCallExpr | |
341 | + { | |
342 | + } | |
343 | + | PostfixExpr T_Inc | |
344 | + { | |
345 | + Operator *op = new Operator(yylloc, (const char *)$2); | |
346 | + $$ = new PostfixExpr($1, op); | |
347 | + } | |
348 | + | PostfixExpr T_Dec | |
349 | + { | |
350 | + Operator *op = new Operator(yylloc, (const char *)$2); | |
351 | + $$ = new PostfixExpr($1, op); | |
352 | + } | |
353 | + | PostfixExpr T_Dot T_FieldSelection | |
354 | + { | |
355 | + Identifier *id = new Identifier(yylloc, (const char *)$3); | |
356 | + $$ = new FieldAccess($1, id); | |
357 | + } | |
358 | + ; | |
359 | + | |
360 | +UnaryExpr : PostfixExpr { $$ = $1; } | |
361 | + | T_Inc UnaryExpr | |
362 | + { | |
363 | + Operator *op = new Operator(yylloc, $1); | |
364 | + $$ = new ArithmeticExpr(op, $2); | |
365 | + } | |
366 | + | T_Dec UnaryExpr | |
367 | + { | |
368 | + Operator *op = new Operator(yylloc, $1); | |
369 | + $$ = new ArithmeticExpr(op, $2); | |
370 | + } | |
371 | + | T_Plus UnaryExpr | |
372 | + { | |
373 | + Operator *op = new Operator(yylloc, $1); | |
374 | + $$ = new ArithmeticExpr(op, $2); | |
375 | + } | |
376 | + | T_Dash UnaryExpr | |
377 | + { | |
378 | + Operator *op = new Operator(yylloc, $1); | |
379 | + $$ = new ArithmeticExpr(op, $2); | |
380 | + } | |
381 | + ; | |
382 | + | |
383 | +MultiExpr : UnaryExpr { $$ = $1; } | |
384 | + | MultiExpr T_Star UnaryExpr | |
385 | + { | |
386 | + Operator *op = new Operator(yylloc, $2); | |
387 | + $$ = new ArithmeticExpr($1, op, $3); | |
388 | + } | |
389 | + | MultiExpr T_Slash UnaryExpr | |
390 | + { | |
391 | + Operator *op = new Operator(yylloc, $2); | |
392 | + $$ = new ArithmeticExpr($1, op, $3); | |
393 | + } | |
394 | + ; | |
395 | + | |
396 | +AdditionExpr : MultiExpr { $$ = $1; } | |
397 | + | AdditionExpr T_Plus MultiExpr | |
398 | + { | |
399 | + Operator *op = new Operator(yylloc, $2); | |
400 | + $$ = new ArithmeticExpr($1, op, $3); | |
401 | + } | |
402 | + | AdditionExpr T_Dash MultiExpr | |
403 | + { | |
404 | + Operator *op = new Operator(yylloc, $2); | |
405 | + $$ = new ArithmeticExpr($1, op, $3); | |
406 | + } | |
407 | + ; | |
408 | + | |
409 | +RelationExpr : AdditionExpr { $$ = $1; } | |
410 | + | RelationExpr T_LeftAngle AdditionExpr | |
411 | + { | |
412 | + Operator *op = new Operator(yylloc, $2); | |
413 | + $$ = new RelationalExpr($1, op, $3); | |
414 | + } | |
415 | + | RelationExpr T_RightAngle AdditionExpr | |
416 | + { | |
417 | + Operator *op = new Operator(yylloc, $2); | |
418 | + $$ = new RelationalExpr($1, op, $3); | |
419 | + } | |
420 | + | RelationExpr T_GreaterEqual AdditionExpr | |
421 | + { | |
422 | + Operator *op = new Operator(yylloc, $2); | |
423 | + $$ = new RelationalExpr($1, op, $3); | |
424 | + } | |
425 | + | RelationExpr T_LessEqual AdditionExpr | |
426 | + { | |
427 | + Operator *op = new Operator(yylloc, $2); | |
428 | + $$ = new RelationalExpr($1, op, $3); | |
429 | + } | |
430 | + ; | |
431 | + | |
432 | +EqualityExpr : RelationExpr { $$ = $1; } | |
433 | + | EqualityExpr T_EQ RelationExpr | |
434 | + { | |
435 | + Operator *op = new Operator(yylloc, $2); | |
436 | + $$ = new ArithmeticExpr($1, op, $3); | |
437 | + } | |
438 | + | EqualityExpr T_NE RelationExpr | |
439 | + { | |
440 | + Operator *op = new Operator(yylloc, $2); | |
441 | + $$ = new ArithmeticExpr($1, op, $3); | |
442 | + } | |
443 | + ; | |
444 | + | |
445 | +LogicAndExpr : EqualityExpr { $$ = $1; } | |
446 | + | LogicAndExpr T_And EqualityExpr | |
447 | + { | |
448 | + Operator *op = new Operator(yylloc, $2); | |
449 | + $$ = new ArithmeticExpr($1, op, $3); | |
450 | + } | |
451 | + ; | |
452 | + | |
453 | +LogicOrExpr : LogicAndExpr { $$ = $1; } | |
454 | + | LogicOrExpr T_Or LogicAndExpr | |
455 | + { | |
456 | + Operator *op = new Operator(yylloc, $2); | |
457 | + $$ = new ArithmeticExpr($1, op, $3); | |
458 | + } | |
459 | + ; | |
460 | + | |
461 | +Expression : LogicOrExpr { $$ = $1; } | |
462 | + | LogicOrExpr T_Question LogicOrExpr T_Colon LogicOrExpr | |
463 | + { | |
464 | + $$ = new ConditionalExpr($1, $3, $5); | |
465 | + } | |
466 | + | UnaryExpr AssignOp Expression | |
467 | + { | |
468 | + $$ = new AssignExpr($1, $2, $3); | |
469 | + } | |
470 | + ; | |
471 | + | |
472 | +AssignOp : T_Equal { $$ = new Operator(yylloc, $1); } | |
473 | + | T_AddAssign { $$ = new Operator(yylloc, "+="); } | |
474 | + | T_SubAssign { $$ = new Operator(yylloc, "-="); } | |
475 | + | T_MulAssign { $$ = new Operator(yylloc, "*="); } | |
476 | + | T_DivAssign { $$ = new Operator(yylloc, "/="); } | |
477 | + ; | |
478 | + | |
479 | +%% | |
480 | + | |
481 | +/* The closing %% above marks the end of the Rules section and the beginning | |
482 | + * of the User Subroutines section. All text from here to the end of the | |
483 | + * file is copied verbatim to the end of the generated y.tab.c file. | |
484 | + * This section is where you put definitions of helper functions. | |
485 | + */ | |
486 | + | |
487 | +/* Function: InitParser | |
488 | + * -------------------- | |
489 | + * This function will be called before any calls to yyparse(). It is designed | |
490 | + * to give you an opportunity to do anything that must be done to initialize | |
491 | + * the parser (set global variables, configure starting state, etc.). One | |
492 | + * thing it already does for you is assign the value of the global variable | |
493 | + * yydebug that controls whether yacc prints debugging information about | |
494 | + * parser actions (shift/reduce) and contents of state stack during parser. | |
495 | + * If set to false, no information is printed. Setting it to true will give | |
496 | + * you a running trail that might be helpful when debugging your parser. | |
497 | + * Please be sure the variable is set to false when submitting your final | |
498 | + * version. | |
499 | + */ | |
500 | +void InitParser() | |
501 | +{ | |
502 | + PrintDebug("parser", "Initializing parser"); | |
503 | + yydebug = false; | |
504 | +} |
public_samples/foo.dat
View file @
c30bbd1
public_samples/foo.glsl
View file @
c30bbd1
public_samples/foo.out
View file @
c30bbd1
... | ... | @@ -0,0 +1 @@ |
1 | +Result: 4 |
public_samples/vec2_test.dat
View file @
c30bbd1
public_samples/vec2_test.glsl
View file @
c30bbd1
public_samples/vec2_test.out
View file @
c30bbd1
... | ... | @@ -0,0 +1 @@ |
1 | +Result: 9.900001e+00 |
runall.sh
View file @
c30bbd1
... | ... | @@ -0,0 +1,17 @@ |
1 | +#! /bin/sh | |
2 | + | |
3 | +[ -x glc ] || { echo "Error: glc not executable"; exit 1; } | |
4 | + | |
5 | +LIST= | |
6 | +if [ "$#" = "0" ]; then | |
7 | + LIST=`ls samples/*.glsl` | |
8 | +else | |
9 | + for test in "$@"; do | |
10 | + LIST="$LIST samples/$test.glsl" | |
11 | + done | |
12 | +fi | |
13 | + | |
14 | +for file in $LIST; do | |
15 | + echo $file | |
16 | + ./glc < $file | |
17 | +done |
scanner.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,23 @@ |
1 | +/* File: scanner.h | |
2 | + * --------------- | |
3 | + * You should not need to modify this file. It declare a few constants, | |
4 | + * types, variables,and functions that are used and/or exported by | |
5 | + * the lex-generated scanner. | |
6 | + */ | |
7 | + | |
8 | +#ifndef _H_scanner | |
9 | +#define _H_scanner | |
10 | + | |
11 | +#include <stdio.h> | |
12 | + | |
13 | +#define MaxIdentLen 31 // Maximum length for identifiers | |
14 | + | |
15 | +extern char *yytext; // Text of lexeme just scanned | |
16 | + | |
17 | + | |
18 | +int yylex(); // Defined in the generated lex.yy.c file | |
19 | + | |
20 | +void InitScanner(); // Defined in scanner.l user subroutines | |
21 | +const char *GetLineNumbered(int n); // ditto | |
22 | + | |
23 | +#endif |
scanner.l
View file @
c30bbd1
... | ... | @@ -0,0 +1,236 @@ |
1 | +/* File: scanner.l | |
2 | + * ---------------- | |
3 | + * Lex input file to generate the scanner for the compiler. | |
4 | + */ | |
5 | + | |
6 | +%{ | |
7 | + | |
8 | +#include <string.h> | |
9 | +#include "scanner.h" | |
10 | +#include "utility.h" // for PrintDebug() | |
11 | +#include "errors.h" | |
12 | +#include "parser.h" // for token codes, yylval | |
13 | +#include <vector> | |
14 | +using namespace std; | |
15 | + | |
16 | +#define TAB_SIZE 8 | |
17 | + | |
18 | +/* Global variables | |
19 | + * ---------------- | |
20 | + * (For shame!) But we need a few to keep track of things that are | |
21 | + * preserved between calls to yylex or used outside the scanner. | |
22 | + */ | |
23 | +static int curLineNum, curColNum; | |
24 | +vector<const char*> savedLines; | |
25 | + | |
26 | +static void DoBeforeEachAction(); | |
27 | +#define YY_USER_ACTION DoBeforeEachAction(); | |
28 | + | |
29 | +%} | |
30 | + | |
31 | +/* States | |
32 | + * ------ | |
33 | + * A little wrinkle on states is the COPY exclusive state which | |
34 | + * I added to first match each line and copy it ot the list of lines | |
35 | + * read before re-processing it. This allows us to print the entire | |
36 | + * line later to provide context on errors. | |
37 | + */ | |
38 | +%s N | |
39 | +%x COPY COMM FIELDS | |
40 | +%option stack | |
41 | + | |
42 | +/* Definitions | |
43 | + * ----------- | |
44 | + * To make our rules more readable, we establish some definitions here. | |
45 | + */ | |
46 | +DIGIT ([0-9]) | |
47 | +HEX_DIGIT ([0-9a-fA-F]) | |
48 | +HEX_INTEGER (0[Xx]{HEX_DIGIT}+) | |
49 | +INTEGER ({DIGIT}+) | |
50 | +EXPONENT ([Ee][-+]?{INTEGER}) | |
51 | +FLOAT ({INTEGER}"."{DIGIT}*[fF]?) | |
52 | +IDENTIFIER ([a-zA-Z][a-zA-Z_0-9]*) | |
53 | +OPERATOR ([-+/*%=.,;!<>()[\]{}:]) | |
54 | +BEG_COMMENT ("/*") | |
55 | +END_COMMENT ("*/") | |
56 | +SINGLE_COMMENT ("//"[^\n]*) | |
57 | + | |
58 | +%% /* BEGIN RULES SECTION */ | |
59 | + | |
60 | +<COPY>.* { char curLine[512]; | |
61 | + //strncpy(curLine, yytext, sizeof(curLine)); | |
62 | + savedLines.push_back(strdup(yytext)); | |
63 | + curColNum = 1; yy_pop_state(); yyless(0); } | |
64 | +<COPY><<EOF>> { yy_pop_state(); } | |
65 | +<*>\n { curLineNum++; curColNum = 1; | |
66 | + if (YYSTATE == COPY) savedLines.push_back(""); | |
67 | + else yy_push_state(COPY); } | |
68 | + | |
69 | +[ ]+ { /* ignore all spaces */ } | |
70 | +<*>[\t] { curColNum += TAB_SIZE - curColNum%TAB_SIZE + 1; } | |
71 | + | |
72 | + /* -------------------- Comments ----------------------------- */ | |
73 | +{BEG_COMMENT} { BEGIN(COMM); } | |
74 | +<COMM>{END_COMMENT} { BEGIN(N); } | |
75 | +<COMM><<EOF>> { ReportError::UntermComment(); | |
76 | + return 0; } | |
77 | +<COMM>. { /* ignore everything else that doesn't match */ } | |
78 | +{SINGLE_COMMENT} { /* skip to end of line for // comment */ } | |
79 | + | |
80 | + | |
81 | + /* --------------------- Keywords ------------------------------- */ | |
82 | +"void" { return T_Void; } | |
83 | +"int" { return T_Int; } | |
84 | +"float" { return T_Float; } | |
85 | +"bool" { return T_Bool; } | |
86 | +"while" { return T_While; } | |
87 | +"for" { return T_For; } | |
88 | +"if" { return T_If; } | |
89 | +"else" { return T_Else; } | |
90 | +"return" { return T_Return; } | |
91 | +"break" { return T_Break; } | |
92 | +"switch" { return T_Switch; } | |
93 | +"case" { return T_Case; } | |
94 | +"default" { return T_Default; } | |
95 | +"const" { return T_Const; } | |
96 | +"uniform" { return T_Uniform; } | |
97 | +"continue" { return T_Continue; } | |
98 | +"do" { return T_Do; } | |
99 | +"in" { return T_In; } | |
100 | +"out" { return T_Out; } | |
101 | +"mat2" { return T_Mat2; } | |
102 | +"mat3" { return T_Mat3; } | |
103 | +"mat4" { return T_Mat4; } | |
104 | +"vec2" { return T_Vec2; } | |
105 | +"vec3" { return T_Vec3; } | |
106 | +"vec4" { return T_Vec4; } | |
107 | +"ivec2" { return T_Ivec2; } | |
108 | +"ivec3" { return T_Ivec3; } | |
109 | +"ivec4" { return T_Ivec4; } | |
110 | +"bvec2" { return T_Bvec2; } | |
111 | +"bvec3" { return T_Bvec3; } | |
112 | +"bvec4" { return T_Bvec4; } | |
113 | +"uint" { return T_Uint; } | |
114 | +"uvec2" { return T_Uvec2; } | |
115 | +"uvec3" { return T_Uvec3; } | |
116 | +"uvec4" { return T_Uvec4; } | |
117 | + | |
118 | + | |
119 | + /* -------------------- punctuation --------------------------- */ | |
120 | +"(" { return T_LeftParen; } | |
121 | +")" { return T_RightParen; } | |
122 | +":" { return T_Colon; } | |
123 | +";" { return T_Semicolon; } | |
124 | +"{" { return T_LeftBrace; } | |
125 | +"}" { return T_RightBrace; } | |
126 | +"." { BEGIN(FIELDS); return T_Dot; } | |
127 | +"[" { return T_LeftBracket; } | |
128 | +"]" { return T_RightBracket; } | |
129 | +"," { return T_Comma; } | |
130 | + | |
131 | + /* -------------------- Operators ----------------------------- */ | |
132 | +"<=" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_LessEqual; } | |
133 | +">=" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_GreaterEqual;} | |
134 | +"==" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_EQ; } | |
135 | +"!=" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_NE; } | |
136 | +"&&" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_And; } | |
137 | +"||" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_Or; } | |
138 | +"++" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_Inc; } | |
139 | +"--" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_Dec; } | |
140 | +"+" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_Plus; } | |
141 | +"-" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_Dash; } | |
142 | +"*" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_Star; } | |
143 | +"/" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_Slash; } | |
144 | +"+=" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_AddAssign; } | |
145 | +"-=" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_SubAssign; } | |
146 | +"*=" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_MulAssign; } | |
147 | +"/=" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_DivAssign; } | |
148 | +"=" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_Equal; } | |
149 | +">" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_RightAngle; } | |
150 | +"<" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_LeftAngle; } | |
151 | +"?" { snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); return T_Question; } | |
152 | + | |
153 | + /* -------------------- Constants ------------------------------ */ | |
154 | +"true"|"false" { yylval.boolConstant = (yytext[0] == 't'); | |
155 | + return T_BoolConstant; } | |
156 | +{INTEGER} { yylval.integerConstant = strtol(yytext, NULL, 10); | |
157 | + return T_IntConstant; } | |
158 | +{HEX_INTEGER} { yylval.integerConstant = strtol(yytext, NULL, 16); | |
159 | + return T_IntConstant; } | |
160 | +{FLOAT} { yylval.floatConstant = atof(yytext); | |
161 | + return T_FloatConstant; } | |
162 | + | |
163 | + | |
164 | + /* -------------------- Identifiers --------------------------- */ | |
165 | +{IDENTIFIER} { if (strlen(yytext) > 1023) | |
166 | + ReportError::LongIdentifier(&yylloc, yytext); | |
167 | + snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); | |
168 | + return T_Identifier; } | |
169 | + | |
170 | + /* -------------------- Field Selection ------------------------- */ | |
171 | +<FIELDS>{IDENTIFIER} { | |
172 | +BEGIN(INITIAL); | |
173 | + // copy the field selection string | |
174 | + if (strlen(yytext) > 1023) | |
175 | + ReportError::LongIdentifier(&yylloc, yytext); | |
176 | + snprintf(yylval.identifier, MaxIdentLen+1, "%s", yytext); | |
177 | + return T_FieldSelection; } | |
178 | +<FIELDS>[ \t\r] {} | |
179 | + | |
180 | + /* -------------------- Default rule (error) -------------------- */ | |
181 | +. { ReportError::UnrecogChar(&yylloc, yytext[0]); } | |
182 | + | |
183 | +%% | |
184 | + | |
185 | + | |
186 | +/* Function: InitScanner | |
187 | + * --------------------- | |
188 | + * This function will be called before any calls to yylex(). It is designed | |
189 | + * to give you an opportunity to do anything that must be done to initialize | |
190 | + * the scanner (set global variables, configure starting state, etc.). One | |
191 | + * thing it already does for you is assign the value of the global variable | |
192 | + * yy_flex_debug that controls whether flex prints debugging information | |
193 | + * about each token and what rule was matched. If set to false, no information | |
194 | + * is printed. Setting it to true will give you a running trail that might | |
195 | + * be helpful when debugging your scanner. Please be sure the variable is | |
196 | + * set to false when submitting your final version. | |
197 | + */ | |
198 | +void InitScanner() | |
199 | +{ | |
200 | + PrintDebug("lex", "Initializing scanner"); | |
201 | + yy_flex_debug = false; | |
202 | + BEGIN(N); | |
203 | + yy_push_state(COPY); // copy first line at start | |
204 | + curLineNum = 1; | |
205 | + curColNum = 1; | |
206 | +} | |
207 | + | |
208 | + | |
209 | +/* Function: DoBeforeEachAction() | |
210 | + * ------------------------------ | |
211 | + * This function is installed as the YY_USER_ACTION. This is a place | |
212 | + * to group code common to all actions. | |
213 | + * On each match, we fill in the fields to record its location and | |
214 | + * update our column counter. | |
215 | + */ | |
216 | +static void DoBeforeEachAction() | |
217 | +{ | |
218 | + yylloc.first_line = curLineNum; | |
219 | + yylloc.first_column = curColNum; | |
220 | + yylloc.last_column = curColNum + yyleng - 1; | |
221 | + curColNum += yyleng; | |
222 | +} | |
223 | + | |
224 | +/* Function: GetLineNumbered() | |
225 | + * --------------------------- | |
226 | + * Returns string with contents of line numbered n or NULL if the | |
227 | + * contents of that line are not available. Our scanner copies | |
228 | + * each line scanned and appends each to a list so we can later | |
229 | + * retrieve them to report the context for errors. | |
230 | + */ | |
231 | +const char *GetLineNumbered(int num) { | |
232 | + if (num <= 0 || num > savedLines.size()) return NULL; | |
233 | + return savedLines[num-1]; | |
234 | +} | |
235 | + | |
236 | + |
submission.sh
View file @
c30bbd1
... | ... | @@ -0,0 +1,58 @@ |
1 | +#!/bin/bash | |
2 | + | |
3 | +name="" | |
4 | +pid="" | |
5 | +email="" | |
6 | + | |
7 | +if [[ $name == "" ]] | |
8 | +then | |
9 | + echo "Edit this script to enter your name and partners name above" | |
10 | + exit | |
11 | +fi | |
12 | + | |
13 | +if [[ $pid == "" ]] | |
14 | +then | |
15 | + echo "Edit this script to enter your PID and partners PID above" | |
16 | + exit | |
17 | +fi | |
18 | + | |
19 | +if [[ $email == "" ]] | |
20 | +then | |
21 | + echo "Edit this script to enter one email where you can be reached easily" | |
22 | + exit | |
23 | +fi | |
24 | + | |
25 | + | |
26 | +if [[ $pid == [A][0-9]* || $pid == [A][0-9]*[_][A][0-9]* || $pid == [A][0-9]*[_][A][0-9]*[_][A][0-9]* ]] | |
27 | +then | |
28 | + rm -rf $pid.zip | |
29 | + rm -rf $pid | |
30 | + | |
31 | + mkdir $pid | |
32 | + | |
33 | + cp Makefile $pid/ | |
34 | + cp README.md $pid/ | |
35 | + cp errors.h $pid/ | |
36 | + cp main.cc $pid/ | |
37 | + cp scanner.h $pid/ | |
38 | + cp utility.h $pid/ | |
39 | + cp Project_Description.txt $pid/ | |
40 | + cp errors.cc $pid/ | |
41 | + cp location.h $pid/ | |
42 | + cp scanner.l $pid/ | |
43 | + cp utility.cc $pid/ | |
44 | + cp ast* $pid/ | |
45 | + cp list.h $pid/ | |
46 | + cp parser.h $pid/ | |
47 | + cp parser.y $pid/ | |
48 | + cp symtable.cc $pid/ | |
49 | + cp symtable.h $pid/ | |
50 | + cp irgen.cc $pid/ | |
51 | + cp irgen.h $pid/ | |
52 | + | |
53 | + zip -r $pid.zip $pid/* | |
54 | +else | |
55 | + echo "The pid provided does not match the criteria on piazza" | |
56 | + exit | |
57 | +fi | |
58 | + |
symtable.cc
View file @
c30bbd1
symtable.h
View file @
c30bbd1
utility.cc
View file @
c30bbd1
... | ... | @@ -0,0 +1,76 @@ |
1 | +/* File: utiliy.cc | |
2 | + * --------------- | |
3 | + * Implementation of simple printing functions to report failures or | |
4 | + * debugging information triggered by keys. | |
5 | + */ | |
6 | + | |
7 | +#include "utility.h" | |
8 | +#include <stdarg.h> | |
9 | +#include <string.h> | |
10 | +#include <vector> | |
11 | +using std::vector; | |
12 | + | |
13 | +static vector<const char*> debugKeys; | |
14 | +static const int BufferSize = 2048; | |
15 | + | |
16 | +void Failure(const char *format, ...) { | |
17 | + va_list args; | |
18 | + char errbuf[BufferSize]; | |
19 | + | |
20 | + va_start(args, format); | |
21 | + vsprintf(errbuf, format, args); | |
22 | + va_end(args); | |
23 | + fflush(stdout); | |
24 | + fprintf(stderr,"\n*** Failure: %s\n\n", errbuf); | |
25 | + abort(); | |
26 | +} | |
27 | + | |
28 | +int IndexOf(const char *key) { | |
29 | + for (unsigned int i = 0; i < debugKeys.size(); i++) | |
30 | + if (!strcmp(debugKeys[i], key)) | |
31 | + return i; | |
32 | + | |
33 | + return -1; | |
34 | +} | |
35 | + | |
36 | +bool IsDebugOn(const char *key) { | |
37 | + return (IndexOf(key) != -1); | |
38 | +} | |
39 | + | |
40 | +void SetDebugForKey(const char *key, bool value) { | |
41 | + int k = IndexOf(key); | |
42 | + if (!value && k != -1) | |
43 | + debugKeys.erase(debugKeys.begin() + k); | |
44 | + else if (value && k == -1) | |
45 | + debugKeys.push_back(key); | |
46 | +} | |
47 | + | |
48 | +void PrintDebug(const char *key, const char *format, ...) { | |
49 | + va_list args; | |
50 | + char buf[BufferSize]; | |
51 | + | |
52 | + if (!IsDebugOn(key)) | |
53 | + return; | |
54 | + | |
55 | + va_start(args, format); | |
56 | + vsprintf(buf, format, args); | |
57 | + va_end(args); | |
58 | + printf("+++ (%s): %s%s", key, buf, buf[strlen(buf)-1] != '\n'? "\n" : ""); | |
59 | +} | |
60 | + | |
61 | +void ParseCommandLine(int argc, char *argv[]) { | |
62 | + if (argc == 1) | |
63 | + return; | |
64 | + | |
65 | + if (strcmp(argv[1], "-d") != 0) { // first arg is not -d | |
66 | + printf("Incorrect Use: "); | |
67 | + for (int i = 1; i < argc; i++) printf("%s ", argv[i]); | |
68 | + printf("\n"); | |
69 | + printf("Correct Usage: -d <debug-key-1> <debug-key-2> ... \n"); | |
70 | + exit(2); | |
71 | + } | |
72 | + | |
73 | + for (int i = 2; i < argc; i++) | |
74 | + SetDebugForKey(argv[i], true); | |
75 | +} | |
76 | + |
utility.h
View file @
c30bbd1
... | ... | @@ -0,0 +1,86 @@ |
1 | +/* File: utility.h | |
2 | + * --------------- | |
3 | + * This file just includes a few support functions you might find | |
4 | + * helpful in writing the projects (error handling, debug printing) | |
5 | + */ | |
6 | + | |
7 | +#ifndef _H_utility | |
8 | +#define _H_utility | |
9 | + | |
10 | +#include <stdlib.h> | |
11 | +#include <stdio.h> | |
12 | + | |
13 | +/** | |
14 | + * Function: Failure() | |
15 | + * Usage: Failure("Out of memory!"); | |
16 | + * -------------------------------- | |
17 | + * Reports an error and exits the program immediately. You should not | |
18 | + * need to call this since you should always try to continue parsing, | |
19 | + * even after an error is encountered. Some of the provided code calls | |
20 | + * this in unrecoverable error situations (cannot allocate memory, etc.) | |
21 | + * Failure accepts printf-style arguments in the message to be printed. | |
22 | + */ | |
23 | + | |
24 | +void Failure(const char *format, ...); | |
25 | + | |
26 | +/** | |
27 | + * Macro: Assert() | |
28 | + * Usage: Assert(num > 0); | |
29 | + * ---------------------- | |
30 | + * This macro is designed to assert the truth of a necessary condition. | |
31 | + * It tests the given expression, and if it evalutes true, nothing happens. | |
32 | + * If it is false, it calls Failure to print a message and abort. | |
33 | + * For example: Assert(ptr != NULL) | |
34 | + * will print something similar to the following if ptr is NULL: | |
35 | + * *** Failure: Assertion failed: hashtable.cc, line 55: | |
36 | + * ptr != NULL | |
37 | + */ | |
38 | + | |
39 | +#define Assert(expr) \ | |
40 | + ((expr) ? (void)0 : Failure("Assertion failed: %s, line %d:\n %s", __FILE__, __LINE__, #expr)) | |
41 | + | |
42 | +/** | |
43 | + * Function: PrintDebug() | |
44 | + * Usage: PrintDebug("parser", "found ident %s\n", ident); | |
45 | + * ------------------------------------------------------- | |
46 | + * Print a message if we have turned debugging messages on for the given | |
47 | + * key. For example, the usage line shown above will only print a message | |
48 | + * if the call is preceded by a call to SetDebugForKey("parser",true). | |
49 | + * The function accepts printf arguments. The provided main.cc parses | |
50 | + * the command line to turn on debug flags. | |
51 | + */ | |
52 | + | |
53 | +void PrintDebug(const char *key, const char *format, ...); | |
54 | + | |
55 | +/** | |
56 | + * Function: SetDebugForKey() | |
57 | + * Usage: SetDebugForKey("scope", true); | |
58 | + * ------------------------------------- | |
59 | + * Turn on debugging messages for the given key. See PrintDebug | |
60 | + * for an example. Can be called manually when desired and will | |
61 | + * be called from the provided main for flags passed with -d. | |
62 | + */ | |
63 | + | |
64 | +void SetDebugForKey(const char *key, bool val); | |
65 | + | |
66 | +/** | |
67 | + * Function: IsDebugOn() | |
68 | + * Usage: if (IsDebugOn("scope")) ... | |
69 | + * ---------------------------------- | |
70 | + * Return true/false based on whether this key is currently on | |
71 | + * for debug printing. | |
72 | + */ | |
73 | + | |
74 | +bool IsDebugOn(const char *key); | |
75 | + | |
76 | +/** | |
77 | + * Function: ParseCommandLine | |
78 | + * -------------------------- | |
79 | + * Turn on the debugging flags from the command line. Verifies that | |
80 | + * first argument is -d, and then interpret all the arguments that follow | |
81 | + * as being flags to turn on. | |
82 | + */ | |
83 | + | |
84 | +void ParseCommandLine(int argc, char *argv[]); | |
85 | + | |
86 | +#endif |