Commit 5b307fe7379cb1e47d4df1f735b8c8a5fc5263f3
1 parent
2531734375
Exists in
master
ummm not sure
Showing 2 changed files with 67 additions and 1 deletions Inline Diff
ast.cc
View file @
5b307fe
/* File: ast.cc | 1 | 1 | /* File: ast.cc | |
* ------------ | 2 | 2 | * ------------ | |
*/ | 3 | 3 | */ | |
4 | 4 | |||
#include "ast.h" | 5 | 5 | #include "ast.h" | |
#include "ast_type.h" | 6 | 6 | #include "ast_type.h" | |
#include "ast_decl.h" | 7 | 7 | #include "ast_decl.h" | |
#include "symtable.h" | 8 | 8 | #include "symtable.h" | |
#include <string.h> // strdup | 9 | 9 | #include <string.h> // strdup | |
#include <stdio.h> // printf | 10 | 10 | #include <stdio.h> // printf | |
11 | 11 | |||
12 | ||||
Node::Node(yyltype loc) { | 12 | 13 | Node::Node(yyltype loc) { | |
location = new yyltype(loc); | 13 | 14 | location = new yyltype(loc); | |
parent = NULL; | 14 | 15 | parent = NULL; | |
} | 15 | 16 | } | |
16 | 17 | |||
Node::Node() { | 17 | 18 | Node::Node() { | |
location = NULL; | 18 | 19 | location = NULL; | |
parent = NULL; | 19 | 20 | parent = NULL; | |
} | 20 | 21 | } | |
21 | 22 | |||
/* The Print method is used to print the parse tree nodes. | 22 | 23 | /* The Print method is used to print the parse tree nodes. | |
* If this node has a location (most nodes do, but some do not), it | 23 | 24 | * If this node has a location (most nodes do, but some do not), it | |
* will first print the line number to help you match the parse tree | 24 | 25 | * will first print the line number to help you match the parse tree | |
* back to the source text. It then indents the proper number of levels | 25 | 26 | * back to the source text. It then indents the proper number of levels | |
* and prints the "print name" of the node. It then will invoke the | 26 | 27 | * and prints the "print name" of the node. It then will invoke the | |
* virtual function PrintChildren which is expected to print the | 27 | 28 | * virtual function PrintChildren which is expected to print the | |
* internals of the node (itself & children) as appropriate. | 28 | 29 | * internals of the node (itself & children) as appropriate. | |
*/ | 29 | 30 | */ | |
void Node::Print(int indentLevel, const char *label) { | 30 | 31 | void Node::Print(int indentLevel, const char *label) { | |
const int numSpaces = 3; | 31 | 32 | const int numSpaces = 3; | |
printf("\n"); | 32 | 33 | printf("\n"); | |
if (GetLocation()) | 33 | 34 | if (GetLocation()) | |
printf("%*d", numSpaces, GetLocation()->first_line); | 34 | 35 | printf("%*d", numSpaces, GetLocation()->first_line); | |
else | 35 | 36 | else | |
printf("%*s", numSpaces, ""); | 36 | 37 | printf("%*s", numSpaces, ""); | |
printf("%*s%s%s: ", indentLevel*numSpaces, "", | 37 | 38 | printf("%*s%s%s: ", indentLevel*numSpaces, "", | |
label? label : "", GetPrintNameForNode()); | 38 | 39 | label? label : "", GetPrintNameForNode()); | |
PrintChildren(indentLevel); | 39 | 40 | PrintChildren(indentLevel); | |
} | 40 | 41 | } | |
41 | 42 | |||
Identifier::Identifier(yyltype loc, const char *n) : Node(loc) { | 42 | 43 | Identifier::Identifier(yyltype loc, const char *n) : Node(loc) { | |
name = strdup(n); | 43 | 44 | name = strdup(n); | |
} | 44 | 45 | } | |
45 | 46 | |||
void Identifier::PrintChildren(int indentLevel) { | 46 | 47 | void Identifier::PrintChildren(int indentLevel) { | |
printf("%s", name); | 47 | 48 | printf("%s", name); | |
49 | } | |||
50 | ||||
51 | /*------------------------------------------------------------------------------------ | |||
52 | * Symbol Table Information | |||
53 | *----------------------------------------------------------------------------------*/ | |||
54 | SymbolTable symbols; | |||
55 | ||||
56 | pair<Decl*,llvm::Value *> findSymbol(string s) { | |||
57 | for(int i = symbols.size() - 1; i >= 0; i--) { | |||
58 | if(symbols[i].count(s) > 0) return symbols[i][s]; | |||
59 | } | |||
60 | return make_pair<Decl*,llvm::Value *>(NULL,NULL); | |||
61 | } | |||
62 | ||||
63 | pair<Decl*,llvm::Value *> findSymbol(Decl* d) { | |||
64 | string s(d->GetIdentifier()->GetName()); | |||
65 | return findSymbol(s); | |||
66 | } | |||
67 | ||||
68 | bool isInCurrentScope(string s) { | |||
69 | if(symbols.size() == 0) return false; | |||
70 | return symbols[symbols.size()-1].count(s); | |||
71 | } | |||
72 | ||||
73 | bool isInCurrentScope(Decl* d) { | |||
74 | string s(d->GetIdentifier()->GetName()); | |||
75 | return isInCurrentScope(s); | |||
76 | } | |||
77 | ||||
78 | bool isInScope(string s) { | |||
79 | pair<Decl*,llvm::Value *> tmp = findSymbol(s); | |||
80 | return tmp.first != NULL; | |||
81 | } | |||
82 | ||||
83 | bool isInScope(Decl* d) { | |||
84 | string s(d->GetIdentifier()->GetName()); | |||
85 | return isInScope(s); | |||
86 | } | |||
87 | ||||
88 | void pushScope() { | |||
89 | symbols.push_back(map<string,pair<Decl*,llvm::Value *> >()); | |||
90 | } | |||
91 | void popScope() { |
ast.h
View file @
5b307fe
/** | 1 | 1 | /** | |
* File: ast.h | 2 | 2 | * File: ast.h | |
* ----------- | 3 | 3 | * ----------- | |
* This file defines the abstract base class Node and the concrete | 4 | 4 | * This file defines the abstract base class Node and the concrete | |
* Identifier and Error node subclasses that are used through the tree as | 5 | 5 | * Identifier and Error node subclasses that are used through the tree as | |
* leaf nodes. A parse tree is a hierarchical collection of ast nodes (or, | 6 | 6 | * leaf nodes. A parse tree is a hierarchical collection of ast nodes (or, | |
* more correctly, of instances of concrete subclassses such as VarDecl, | 7 | 7 | * more correctly, of instances of concrete subclassses such as VarDecl, | |
* ForStmt, and AssignExpr). | 8 | 8 | * ForStmt, and AssignExpr). | |
* | 9 | 9 | * | |
* Location: Each node maintains its lexical location (line and columns in | 10 | 10 | * Location: Each node maintains its lexical location (line and columns in | |
* file), that location can be NULL for those nodes that don't care/use | 11 | 11 | * file), that location can be NULL for those nodes that don't care/use | |
* locations. The location is typcially set by the node constructor. The | 12 | 12 | * locations. The location is typcially set by the node constructor. The | |
* location is used to provide the context when reporting semantic errors. | 13 | 13 | * location is used to provide the context when reporting semantic errors. | |
* | 14 | 14 | * | |
* Parent: Each node has a pointer to its parent. For a Program node, the | 15 | 15 | * Parent: Each node has a pointer to its parent. For a Program node, the | |
* parent is NULL, for all other nodes it is the pointer to the node one level | 16 | 16 | * parent is NULL, for all other nodes it is the pointer to the node one level | |
* up in the parse tree. The parent is not set in the constructor (during a | 17 | 17 | * up in the parse tree. The parent is not set in the constructor (during a | |
* bottom-up parse we don't know the parent at the time of construction) but | 18 | 18 | * bottom-up parse we don't know the parent at the time of construction) but | |
* instead we wait until assigning the children into the parent node and then | 19 | 19 | * instead we wait until assigning the children into the parent node and then | |
* set up links in both directions. The parent link is typically not used | 20 | 20 | * set up links in both directions. The parent link is typically not used | |
* during parsing, but is more important in later phases. | 21 | 21 | * during parsing, but is more important in later phases. | |
* | 22 | 22 | * | |
* Printing: This functionaility is saved from pp2 of the node classes to | 23 | 23 | * Printing: This functionaility is saved from pp2 of the node classes to | |
* print out the AST tree for debugging purpose. Each node class is | 24 | 24 | * print out the AST tree for debugging purpose. Each node class is | |
* responsible for printing itself/children by overriding the virtual | 25 | 25 | * responsible for printing itself/children by overriding the virtual | |
* PrintChildren() and GetPrintNameForNode() methods. All the classes we | 26 | 26 | * PrintChildren() and GetPrintNameForNode() methods. All the classes we | |
* provide already implement these methods, so your job is to construct the | 27 | 27 | * provide already implement these methods, so your job is to construct the | |
* nodes and wire them up during parsing. Once that's done, printing is a snap! | 28 | 28 | * nodes and wire them up during parsing. Once that's done, printing is a snap! | |
29 | 29 | |||
* Semantic analysis: For pp3 you are adding "Check" behavior to the ast | 30 | 30 | * Semantic analysis: For pp3 you are adding "Check" behavior to the ast | |
* node classes. Your semantic analyzer should do an inorder walk on the | 31 | 31 | * node classes. Your semantic analyzer should do an inorder walk on the | |
* parse tree, and when visiting each node, verify the particular | 32 | 32 | * parse tree, and when visiting each node, verify the particular | |
* semantic rules that apply to that construct. | 33 | 33 | * semantic rules that apply to that construct. | |
34 | 34 | |||
*/ | 35 | 35 | */ | |
36 | 36 | |||
#ifndef _H_ast | 37 | 37 | #ifndef _H_ast | |
#define _H_ast | 38 | 38 | #define _H_ast | |
39 | 39 | |||
#include <stdlib.h> // for NULL | 40 | 40 | #include <stdlib.h> // for NULL | |
#include "irgen.h" | 41 | 41 | #include "irgen.h" | |
#include "location.h" | 42 | 42 | #include "location.h" | |
#include <iostream> | 43 | 43 | #include <iostream> | |
44 | #include <vector> | |||
45 | #include <map> | |||
46 | #include <algorithm> | |||
44 | 47 | |||
using namespace std; | 45 | 48 | using namespace std; | |
46 | 49 | |||
class SymbolTable; | 47 | 50 | class SymbolTable; | |
class MyStack; | 48 | 51 | class MyStack; | |
class FnDecl; | 49 | 52 | class FnDecl; | |
53 | class Decl; | |||
50 | 54 | |||
class Node { | 51 | 55 | class Node { | |
protected: | 52 | 56 | protected: | |
yyltype *location; | 53 | 57 | yyltype *location; | |
Node *parent; | 54 | 58 | Node *parent; | |
55 | 59 | |||
public: | 56 | 60 | public: | |
Node(yyltype loc); | 57 | 61 | Node(yyltype loc); | |
Node(); | 58 | 62 | Node(); | |
virtual ~Node() {} | 59 | 63 | virtual ~Node() {} | |
60 | 64 | |||
yyltype *GetLocation() { return location; } | 61 | 65 | yyltype *GetLocation() { return location; } | |
void SetParent(Node *p) { parent = p; } | 62 | 66 | void SetParent(Node *p) { parent = p; } | |
Node *GetParent() { return parent; } | 63 | 67 | Node *GetParent() { return parent; } | |
64 | 68 | |||
virtual const char *GetPrintNameForNode() = 0; | 65 | 69 | virtual const char *GetPrintNameForNode() = 0; | |
66 | 70 | |||
// Print() is deliberately _not_ virtual | 67 | 71 | // Print() is deliberately _not_ virtual | |
// subclasses should override PrintChildren() instead | 68 | 72 | // subclasses should override PrintChildren() instead | |
void Print(int indentLevel, const char *label = NULL); | 69 | 73 | void Print(int indentLevel, const char *label = NULL); | |
virtual void PrintChildren(int indentLevel) {} | 70 | 74 | virtual void PrintChildren(int indentLevel) {} | |
71 | 75 | |||
virtual llvm::Value* Emit() { return NULL; } | 72 | 76 | virtual llvm::Value* Emit() { return NULL; } | |
}; | 73 | 77 | }; | |
74 | 78 | |||
75 | 79 | |||
class Identifier : public Node | 76 | 80 | class Identifier : public Node | |
{ | 77 | 81 | { | |
protected: | 78 | 82 | protected: | |
char *name; | 79 | 83 | char *name; | |
80 | 84 | |||
public: | 81 | 85 | public: | |
Identifier(yyltype loc, const char *name); | 82 | 86 | Identifier(yyltype loc, const char *name); | |
const char *GetPrintNameForNode() { return "Identifier"; } | 83 | 87 | const char *GetPrintNameForNode() { return "Identifier"; } | |
char *GetName() const { return name; } | 84 | 88 | char *GetName() const { return name; } | |
void PrintChildren(int indentLevel); | 85 | 89 | void PrintChildren(int indentLevel); | |
friend ostream& operator<<(ostream& out, Identifier *id) { return out << id->name; } | 86 | 90 | friend ostream& operator<<(ostream& out, Identifier *id) { return out << id->name; } | |
}; | 87 | 91 | }; | |
88 | 92 | |||
89 | 93 | |||
// This node class is designed to represent a portion of the tree that | 90 | 94 | // This node class is designed to represent a portion of the tree that | |
// encountered syntax errors during parsing. The partial completed tree | 91 | 95 | // encountered syntax errors during parsing. The partial completed tree | |
// is discarded along with the states being popped, and an instance of | 92 | 96 | // is discarded along with the states being popped, and an instance of | |
// the Error class can stand in as the placeholder in the parse tree | 93 | 97 | // the Error class can stand in as the placeholder in the parse tree | |
// when your parser can continue after an error. | 94 | 98 | // when your parser can continue after an error. | |
class Error : public Node | 95 | 99 | class Error : public Node | |
{ | 96 | 100 | { | |
public: | 97 | 101 | public: | |
Error() : Node() {} | 98 | 102 | Error() : Node() {} |