Last active
November 14, 2018 00:03
-
-
Save mikeymop/78209e89d447a5c796e1ba56216738b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* lex.cpp | |
* | |
* CS280 - Fall 2018 | |
*/ | |
#include <cctype> | |
#include <map> | |
using std::map; | |
#include "tokens.h" | |
static map<TokenType,string> tokenPrint = { | |
{ IF, "IF" }, | |
{ THEN, "THEN" }, | |
{ PRINT, "PRINT" }, | |
{ TRUE, "TRUE" }, | |
{ FALSE, "FALSE" }, | |
{ IDENT, "IDENT" }, | |
{ ICONST, "ICONST" }, | |
{ SCONST, "SCONST" }, | |
{ PLUS, "PLUS" }, | |
{ MINUS, "MINUS" }, | |
{ STAR, "STAR" }, | |
{ SLASH, "SLASH" }, | |
{ ASSIGN, "ASSIGN" }, | |
{ EQ, "EQ" }, | |
{ NEQ, "NEQ" }, | |
{ LT, "LT" }, | |
{ LEQ, "LEQ" }, | |
{ GT, "GT" }, | |
{ GEQ, "GEQ" }, | |
{ LOGICAND, "LOGICAND" }, | |
{ LOGICOR, "LOGICOR" }, | |
{ SC, "SC" }, | |
{ ERR, "ERR" }, | |
{ DONE, "DONE" } | |
}; | |
ostream& operator<<(ostream& out, const Token& tok) { | |
TokenType tt = tok.GetTokenType(); | |
out << tokenPrint[ tt ]; | |
if( tt == IDENT || tt == ICONST || tt == SCONST || tt == ERR ) { | |
out << "(" << tok.GetLexeme() << ")"; | |
} | |
return out; | |
} | |
static map<string,TokenType> kwmap = { | |
{ "if", IF }, | |
{ "then", THEN }, | |
{ "print", PRINT }, | |
{ "true", TRUE }, | |
{ "false", FALSE }, | |
}; | |
Token | |
id_or_kw(const string& lexeme, int linenum) | |
{ | |
TokenType tt = IDENT; | |
auto kIt = kwmap.find(lexeme); | |
if( kIt != kwmap.end() ) | |
tt = kIt->second; | |
return Token(tt, lexeme, linenum); | |
} | |
// macro to putback and decrement if newline | |
// the string PB is replaced by this block of code... it's a little hacky | |
#define PB { in->putback(ch); if( ch == '\n' ) (*linenum)--; } | |
// inline function to putback and decrement if newline | |
// this is cleaner but longer to call | |
inline void PutBack(char ch, istream *in, int *linenum) { | |
in->putback(ch); | |
if( ch == '\n' ) | |
(*linenum)--; | |
} | |
// another version of the macro could have been | |
#define PB2(ch,in,linenum) { in->putback(ch); if( ch == '\n' ) (*linenum)--; } | |
Token | |
getNextToken(istream *in, int *linenum) | |
{ | |
enum LexState { BEGIN, INID, INSTRING, SAWEQ, SAWLT, SAWGT, SAWAND, SAWOR, SAWNOT, ININT, INCOMMENT } lexstate = BEGIN; | |
string lexeme; | |
char ch; | |
while(in->get(ch)) { | |
if( ch == '\n' ) { | |
(*linenum)++; | |
} | |
switch( lexstate ) { | |
case BEGIN: | |
if( isspace(ch) ) | |
continue; | |
lexeme = ch; | |
if( isalpha(ch) ) { | |
lexstate = INID; | |
} | |
else if( ch == '"' ) { | |
lexstate = INSTRING; | |
} | |
else if( ch == '=' ) { | |
lexstate = SAWEQ; | |
} | |
else if( ch == '!' ) { | |
if( in->peek() == '=' ) { | |
in->get(ch); | |
return Token(NEQ, "!=", *linenum); | |
} | |
else { | |
if( in->peek() == '\n' ) | |
(*linenum)++; | |
return Token(ERR, "!", *linenum); | |
} | |
} | |
else if( ch == '>' ) { | |
lexstate = SAWGT; | |
} | |
else if( ch == '<' ) { | |
lexstate = SAWLT; | |
} | |
else if( ch == '&' ) { | |
lexstate = SAWAND; | |
} | |
else if( ch == '|' ) { | |
lexstate = SAWOR; | |
} | |
else if( ch == '!' ) { | |
lexstate = SAWNOT; | |
} | |
else if( isdigit(ch) ) { | |
lexstate = ININT; | |
} | |
else if( ch == '#' ) { | |
lexstate = INCOMMENT; | |
} | |
else { | |
TokenType tt = ERR; | |
switch( ch ) { | |
case '+': | |
tt = PLUS; | |
break; | |
case '-': | |
tt = MINUS; | |
break; | |
case '*': | |
tt = STAR; | |
break; | |
case '/': | |
tt = SLASH; | |
break; | |
case '(': | |
tt = LPAREN; | |
break; | |
case ')': | |
tt = RPAREN; | |
break; | |
case ';': | |
tt = SC; | |
break; | |
} | |
return Token(tt, lexeme, *linenum); | |
} | |
break; | |
case INID: | |
if( isalpha(ch) || isdigit(ch) ) { | |
lexeme += ch; | |
} | |
else { | |
if( ch == '\n' ) | |
(*linenum)--; | |
in->putback(ch); | |
return id_or_kw(lexeme, *linenum); | |
} | |
break; | |
case INSTRING: | |
lexeme += ch; | |
if( ch == '\n' ) { | |
return Token(ERR, lexeme, *linenum ); | |
} | |
if( ch == '"' ) { | |
lexeme = lexeme.substr(1, lexeme.length()-2); | |
return Token(SCONST, lexeme, *linenum ); | |
} | |
break; | |
case SAWEQ: | |
if( ch == '=' ) | |
return Token(EQ, lexeme, *linenum); | |
else { | |
PB | |
return Token(ASSIGN, lexeme, *linenum); | |
} | |
break; | |
case SAWGT: | |
if( ch == '=' ) | |
return Token(GEQ, lexeme, *linenum); | |
else { | |
PutBack(ch, in, linenum); | |
return Token(GT, lexeme, *linenum); | |
} | |
break; | |
case SAWLT: | |
if( ch == '=' ) | |
return Token(LEQ, lexeme, *linenum); | |
else { | |
if( ch == '\n' ) | |
(*linenum)--; | |
in->putback(ch); | |
return Token(LT, lexeme, *linenum); | |
} | |
break; | |
case SAWAND: | |
if( ch == '&' ) | |
return Token(LOGICAND, lexeme, *linenum); | |
else { | |
return Token(ERR, lexeme, *linenum); | |
} | |
break; | |
case SAWOR: | |
if( ch == '|' ) | |
return Token(LOGICOR, lexeme, *linenum); | |
else { | |
return Token(ERR, lexeme, *linenum); | |
} | |
break; | |
case SAWNOT: | |
if( ch == '=' ) | |
return Token(NEQ, lexeme, *linenum); | |
else { | |
return Token(ERR, lexeme, *linenum); | |
} | |
break; | |
case ININT: | |
if( isdigit(ch) ) { | |
lexeme += ch; | |
} | |
else if( isalpha(ch) ) { | |
lexeme += ch; | |
return Token(ERR, lexeme, *linenum); | |
} | |
else { | |
if( ch == '\n' ) | |
(*linenum)--; | |
in->putback(ch); | |
return Token(ICONST, lexeme, *linenum); | |
} | |
break; | |
case INCOMMENT: | |
if( ch == '\n' ) { | |
lexstate = BEGIN; | |
} | |
break; | |
} | |
} | |
if( in->eof() ) | |
return Token(DONE, "", *linenum); | |
return Token(ERR, "some strange I/O error", *linenum); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* main.cpp | |
*/ | |
#include "tokens.h" | |
#include "parse.h" | |
#include "parsetree.h" | |
#include "tokens.h" | |
#include <iostream> | |
#include <fstream> | |
#include <string.h> | |
using std::cin; | |
using std::cout; | |
using std::endl; | |
using std::ifstream; | |
/* | |
array<string, 4> names = {"ERRTYPE", "INTTYPE", "STRTYPE", "BOOLTYPE"}; | |
//Demangles class names when printing them out for debugging. | |
string demangle(const char* name) { | |
int status; | |
char* demangledName = abi::__cxa_demangle(name, nullptr, nullptr, &status); | |
string retVal = string(demangledName); | |
free(demangledName); | |
return retVal; | |
} | |
// Prints out the parse tree if debug is enabled. | |
void debugPrint(ParseTree* tree, uint level = 0) { | |
ParseTree* currTree = tree->getLeft(); | |
string className = demangle(typeid(*tree).name()); | |
cout << string(level, '\t') << className << string(8 - level - className.length() / 4, '\t') << names[tree->GetType()] << '\n'; | |
if (currTree) | |
debugPrint(currTree, level + 1); | |
currTree = tree->getRight(); | |
if (currTree) | |
debugPrint(currTree, level + (tree->GetType() != treeType::STMTLIST)); | |
} | |
*/ | |
void ParseOut(ParseTree *prog); | |
int main(int argc, char *argv[]) { | |
ifstream ifile; | |
istream *in; | |
int linenum = 0; | |
//Token tok; | |
// CHECK ARGUMENTS, OPEN FILES | |
if(argc == 1) { | |
in = &cin; | |
} | |
if(argc > 2) { | |
cout << "TOO MANY FILENAMES" << endl; | |
return 1; | |
} | |
if(argc == 2) { | |
ifile.open(argv[1]); | |
if(!ifile.is_open()) { | |
string x = argv[1]; | |
cout << "COULD NOT OPEN " << x << endl; | |
return 2; | |
} | |
} else { | |
in = &ifile; | |
} | |
ParseTree *prog = Prog(in, &linenum); | |
if( prog == 0 ) | |
return 0; // quit on error | |
ParseOut(prog); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* parse.cpp | |
*/ | |
#include "parse.h" | |
#include "parsetree.h" | |
#include "tokens.h" | |
#include <string.h> | |
#include <vector> | |
#include <algorithm> | |
/* GRAMMAR | |
Prog := Slist | |
Slist := Stmt SC { Slist } | |
Stmt := IfStmt | PrintStmt | Expr | |
IfStmt := IF Expr THEN Stmt | |
PrintStmt := PRINT Expr | |
Expr := LogicExpr { ASSIGN LogicExpr } | |
LogicExpr := CompareExpr { (LOGICAND | LOGICOR) CompareExpr } | |
CompareExpr := AddExpr { (EQ | NEQ | GT | GEQ | LT | LEQ) AddExpr } | |
AddExpr := MulExpr { (PLUS | MINUS) MulExpr } | |
MulExpr := Factor { (STAR | SLASH) Factor } | |
Factor := MINUS Primary | Primary | |
Primary := IDENT | ICONST | SCONST | TRUE | FALSE | LPAREN Expr | |
RPAREN | |
*/ | |
//int stringct = 0; | |
int identct = 0; | |
std::string tempWord = ""; | |
std::vector<std::string> idents; | |
void ParseOut(ParseTree *prog) { | |
cout << "LEAF COUNT: " << prog->LeafCount() << endl; | |
cout << "STRING COUNT: " << prog->StringCount() << endl; | |
if(identct != 0) { | |
cout << "IDENT COUNT: " << identct << endl; | |
//need alphabetical order | |
sort(idents.begin(), idents.end()); | |
//have to remove dupes | |
idents.erase(unique(idents.begin(), idents.end()), idents.end()); | |
//cout << "IDENTIFIERS: "; | |
for (int i = 0; i <= idents.size() - 1; ++i) { | |
if(i == idents.size()-1) { | |
cout << idents[i] << endl; | |
} else { | |
cout << idents[i] << ", "; | |
} | |
} | |
} | |
} | |
// WRAPPER FOR PUSHBACK | |
namespace Parser { | |
bool pushed_back = false; | |
Token pushed_token; | |
static Token GetNextToken(istream *in, int *line) { | |
if( pushed_back ) { | |
pushed_back = false; | |
return pushed_token; | |
} | |
return getNextToken(in, line); | |
} | |
static void PushBackToken(Token& t) { | |
if( pushed_back ) { | |
abort(); | |
} | |
pushed_back = true; | |
pushed_token = t; | |
} | |
} | |
static int error_count = 0; | |
void ParseError(int line, string msg) { | |
++error_count; | |
cout << line << ": " << msg << endl; | |
} | |
ParseTree *Prog(istream *in, int *line) { | |
ParseTree *sl = Slist(in, line); | |
if( sl == 0 ) | |
ParseError(*line, "No statements in program"); | |
if( error_count ) | |
return 0; | |
return sl; | |
} | |
// Slist is a Statement followed by a Statement List | |
ParseTree *Slist(istream *in, int *line) { | |
ParseTree *s = Stmt(in, line); | |
if( s == 0 ) | |
return 0; | |
if( Parser::GetNextToken(in, line) != SC ) { | |
ParseError(*line, "Missing semicolon"); | |
return 0; | |
} | |
return new StmtList(s, Slist(in,line)); | |
} | |
ParseTree *Stmt(istream *in, int *line) { | |
ParseTree *s; | |
Token t = Parser::GetNextToken(in, line); | |
switch( t.GetTokenType() ) { | |
case IF: | |
s = IfStmt(in, line); | |
break; | |
case PRINT: | |
s = PrintStmt(in, line); | |
break; | |
case DONE: | |
return 0; | |
case ERR: | |
ParseError(*line, "Invalid token"); | |
return 0; | |
default: | |
// put back the token and then see if it's an Expr | |
Parser::PushBackToken(t); | |
s = Expr(in, line); | |
if( s == 0 ) { | |
ParseError(*line, "Invalid statement"); | |
return 0; | |
} | |
break; | |
} | |
return s; | |
} | |
ParseTree *IfStmt(istream *in, int *line) { | |
//assume next node is Expr | |
ParseTree *ex = Expr(in, line); | |
if (ex == 0) { | |
ParseError(*line, "Invalid statement"); | |
return 0; | |
} | |
Token t = Parser::GetNextToken(in, line); | |
ParseTree *stmt = Stmt(in, line); | |
if(t.GetTokenType() != THEN ) { | |
ParseError(*line, "If statement screwed up"); | |
return 0; | |
} | |
if(stmt == 0) { | |
ParseError(*line, "Invalid statement"); | |
} | |
return new IfStatement(t.GetLinenum(), ex, stmt); | |
} | |
ParseTree *PrintStmt(istream *in, int *line) { | |
// ADD HANDLER | |
// if parse tree type is printstatement add it to parse tree list? | |
ParseTree *ex = Expr(in, line); | |
if(ex == 0) { | |
ParseError(*line, "Bad prt stmt"); | |
return 0; | |
} | |
return new PrintStatement(ex->GetLinenum(), ex); | |
} | |
ParseTree *Expr(istream *in, int *line) { | |
ParseTree *t1 = LogicExpr(in, line); | |
if( t1 == 0 ) { | |
return 0; | |
} | |
Token t = Parser::GetNextToken(in, line); | |
if( t != ASSIGN ) { | |
Parser::PushBackToken(t); | |
return t1; | |
} | |
ParseTree *t2 = Expr(in, line); // right assoc | |
if( t2 == 0 ) { | |
ParseError(*line, "Missing expression after operator"); | |
return 0; | |
} | |
return new Assignment(t2->GetLinenum(), t1, t2); | |
} | |
ParseTree *LogicExpr(istream *in, int *line) { | |
ParseTree *t1 = CompareExpr(in, line); | |
if( t1 == 0 ) { | |
return 0; | |
} | |
// HANDLE OP | |
while (true) { | |
Token t = Parser::GetNextToken(in, line); | |
if(t != LOGICAND && t != LOGICOR) { | |
Parser::PushBackToken(t); | |
return t1; | |
} | |
//right node | |
ParseTree *t2 = CompareExpr(in, line); | |
//if its not a valid expr for right leaf | |
if(t2 == 0) { | |
ParseError(*line, "Missing expression after op"); | |
return 0; | |
} | |
//return right leaf | |
if(t == LOGICAND) { | |
return new LogicAndExpr(t.GetLinenum(), t1, t2); | |
} else { | |
return new LogicOrExpr(t.GetLinenum(), t1, t2); | |
} | |
} | |
return 0; | |
} | |
ParseTree *CompareExpr(istream *in, int *line) { | |
ParseTree *t1 = AddExpr(in, line); | |
if( t1 == 0 ) { | |
return 0; | |
} | |
// HANDLE OP | |
while (true) { | |
Token t = Parser::GetNextToken(in, line); | |
if(t != EQ && t != NEQ && t != LT && t != LEQ && t != GT && t != GEQ) { | |
Parser::PushBackToken(t); | |
return t1; | |
} | |
//right node | |
ParseTree *t2 = CompareExpr(in, line); | |
//if its not a valid expr for right leaf | |
if(t2 == 0) { | |
ParseError(*line, "Missing expression after op"); | |
return 0; | |
} | |
//return right leaf | |
switch(t.GetTokenType()) { | |
case EQ: | |
return new EqExpr(t.GetLinenum(), t1, t2); | |
case NEQ: | |
return new NEqExpr(t.GetLinenum(), t1, t2); | |
case LT: | |
return new LtExpr(t.GetLinenum(), t1, t2); | |
case LEQ: | |
return new LEqExpr(t.GetLinenum(), t1, t2); | |
case GT: | |
return new GtExpr(t.GetLinenum(), t1, t2); | |
case GEQ: | |
return new GEqExpr(t.GetLinenum(), t1, t2); | |
default: | |
return 0; | |
} | |
} | |
//return 0; | |
} | |
ParseTree *AddExpr(istream *in, int *line) { | |
ParseTree *t1 = MulExpr(in, line); | |
if( t1 == 0 ) { | |
return 0; | |
} | |
while ( true ) { | |
Token t = Parser::GetNextToken(in, line); | |
if( t != PLUS && t != MINUS ) { | |
Parser::PushBackToken(t); | |
return t1; | |
} | |
ParseTree *t2 = MulExpr(in, line); | |
if( t2 == 0 ) { | |
ParseError(*line, "Missing expression after operator"); | |
return 0; | |
} | |
if( t == PLUS ) | |
t1 = new PlusExpr(t.GetLinenum(), t1, t2); | |
else | |
t1 = new MinusExpr(t.GetLinenum(), t1, t2); | |
} | |
} | |
ParseTree *MulExpr(istream *in, int *line) { | |
ParseTree *t1 = Factor(in, line); | |
if( t1 == 0 ) { | |
return 0; | |
} | |
// HANDLE OP | |
while ( true ) { | |
Token t = Parser::GetNextToken(in, line); | |
if(t != STAR && t != SLASH) { | |
Parser::PushBackToken(t); | |
return t1; | |
} | |
//2nd factor | |
ParseTree *t2 = Factor(in, line); | |
if( t2 == 0 ) { | |
ParseError(*line, "Missing expression after operator"); | |
return 0; | |
} | |
//return the expressions | |
if( t != STAR ) | |
t1 = new TimesExpr(t.GetLinenum(), t1, t2); | |
else | |
t1 = new DivideExpr(t.GetLinenum(), t1, t2); | |
} | |
} | |
ParseTree *Factor(istream *in, int *line) { | |
bool neg = false; | |
Token t = Parser::GetNextToken(in, line); | |
if( t == MINUS ) { | |
neg = true; | |
} | |
else { | |
Parser::PushBackToken(t); | |
} | |
ParseTree *p1 = Primary(in, line); | |
if( p1 == 0 ) { | |
ParseError(*line, "Missing primary"); | |
return 0; | |
} | |
if( neg ) { | |
// handle as -1 * Primary | |
return new TimesExpr(t.GetLinenum(), new IConst(t.GetLinenum(), -1), p1); | |
} | |
else | |
return p1; | |
} | |
ParseTree *Primary(istream *in, int *line) { | |
Token t = Parser::GetNextToken(in, line); | |
// PROCESS TOKEN, IDENTIFY PRIMARY, RETURN SOMETHING | |
switch( t.GetTokenType() ) { | |
case IDENT: | |
//make ident map and append to it | |
identct++; | |
tempWord = t.GetLexeme(); | |
idents.push_back(tempWord); | |
return new Ident(t); | |
case ICONST: | |
return new IConst(t); | |
case SCONST: | |
return new SConst(t); | |
case TRUE: | |
return new BoolConst(t, TRUE); | |
case FALSE: | |
return new BoolConst(t, FALSE); | |
case LPAREN: | |
{ | |
ParseTree *ex = Expr(in, line); | |
Token t1 = Parser::GetNextToken(in, line); | |
if (t1 != RPAREN) { | |
ParseError(t1.GetLinenum(), "Syntax Err"); | |
Parser::PushBackToken(t1); | |
return 0; | |
} else { | |
return ex; | |
} | |
} | |
default: | |
// put back the token and then see if it's an Expr | |
Parser::PushBackToken(t); | |
ParseError(*line, "Invalid statement"); | |
return 0; | |
}//case | |
}//Parsetree |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* parse.h | |
*/ | |
/* GRAMMAR | |
Prog := Slist | |
Slist := Stmt SC { Slist } | |
Stmt := IfStmt | PrintStmt | Expr | |
-+IfStmt := IF Expr THEN Stmt | |
+PrintStmt := PRINT Expr | |
Expr := LogicExpr { ASSIGN LogicExpr } | |
-+LogicExpr := CompareExpr { (LOGICAND | LOGICOR) CompareExpr } | |
-+CompareExpr := AddExpr { (EQ | NEQ | GT | GEQ | LT | LEQ) AddExpr } | |
AddExpr := MulExpr { (PLUS | MINUS) MulExpr } | |
-+MulExpr := Factor { (STAR | SLASH) Factor } | |
Factor := MINUS Primary | Primary | |
-+Primary := IDENT | ICONST | SCONST | TRUE | FALSE | LPAREN Expr | |
RPAREN | |
*/ | |
#ifndef PARSE_H_ | |
#define PARSE_H_ | |
#include <iostream> | |
using namespace std; | |
#include "tokens.h" | |
#include "parsetree.h" | |
extern ParseTree *Prog(istream *in, int *line); | |
extern ParseTree *Slist(istream *in, int *line); | |
extern ParseTree *Stmt(istream *in, int *line); | |
extern ParseTree *IfStmt(istream *in, int *line); | |
extern ParseTree *PrintStmt(istream *in, int *line); | |
extern ParseTree *Expr(istream *in, int *line); | |
extern ParseTree *LogicExpr(istream *in, int *line); | |
extern ParseTree *CompareExpr(istream *in, int *line); | |
extern ParseTree *AddExpr(istream *in, int *line); | |
extern ParseTree *MulExpr(istream *in, int *line); | |
extern ParseTree *Factor(istream *in, int *line); | |
extern ParseTree *Primary(istream *in, int *line); | |
#endif /* PARSE_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* parsetree.h | |
*/ | |
#ifndef PARSETREE_H_ | |
#define PARSETREE_H_ | |
#include <vector> | |
#include <map> | |
using std::vector; | |
using std::map; | |
// NodeType represents all possible types | |
enum NodeType { ERRTYPE, INTTYPE, STRTYPE, BOOLTYPE }; | |
// a "forward declaration" for a class to hold values | |
class Value; | |
class ParseTree { | |
int linenum; | |
ParseTree *left; | |
ParseTree *right; | |
public: | |
ParseTree(int linenum, ParseTree *l = 0, ParseTree *r = 0) | |
: linenum(linenum), left(l), right(r) {} | |
virtual ~ParseTree() { | |
delete left; | |
delete right; | |
} | |
int GetLinenum() const { return linenum; } | |
virtual NodeType GetType() const { return ERRTYPE; } | |
int LeafCount() const { | |
int lc = 0; | |
if( left ) lc += left->LeafCount(); | |
if( right ) lc += right->LeafCount(); | |
if( left == 0 && right == 0 ) | |
lc++; | |
return lc; | |
} | |
// other methods | |
int StringCount() const { | |
int sc = 0; | |
if( left ) sc += left->LeafCount(); | |
if( right ) sc += right->LeafCount(); | |
if((*this).GetType() == STRTYPE) | |
sc++; | |
return sc; | |
} | |
}; | |
class StmtList : public ParseTree { | |
public: | |
StmtList(ParseTree *l, ParseTree *r) : ParseTree(0, l, r) {} | |
}; | |
class IfStatement : public ParseTree { | |
public: | |
IfStatement(int line, ParseTree *ex, ParseTree *stmt) : ParseTree(line, ex, stmt) {} | |
}; | |
class Assignment : public ParseTree { | |
public: | |
Assignment(int line, ParseTree *lhs, ParseTree *rhs) : ParseTree(line, lhs, rhs) {} | |
}; | |
class PrintStatement : public ParseTree { | |
public: | |
PrintStatement(int line, ParseTree *e) : ParseTree(line, e) {} | |
}; | |
class PlusExpr : public ParseTree { | |
public: | |
PlusExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class MinusExpr : public ParseTree { | |
public: | |
MinusExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class TimesExpr : public ParseTree { | |
public: | |
TimesExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class DivideExpr : public ParseTree { | |
public: | |
DivideExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class LogicAndExpr : public ParseTree { | |
public: | |
LogicAndExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class LogicOrExpr : public ParseTree { | |
public: | |
LogicOrExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class EqExpr : public ParseTree { | |
public: | |
EqExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class NEqExpr : public ParseTree { | |
public: | |
NEqExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class LtExpr : public ParseTree { | |
public: | |
LtExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class LEqExpr : public ParseTree { | |
public: | |
LEqExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class GtExpr : public ParseTree { | |
public: | |
GtExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class GEqExpr : public ParseTree { | |
public: | |
GEqExpr(int line, ParseTree *l, ParseTree *r) : ParseTree(line,l,r) {} | |
}; | |
class IConst : public ParseTree { | |
int val; | |
public: | |
IConst(int l, int i) : ParseTree(l), val(i) {} | |
IConst(Token& t) : ParseTree(t.GetLinenum()) { | |
val = stoi(t.GetLexeme()); | |
} | |
NodeType GetType() const { return INTTYPE; } | |
}; | |
class BoolConst : public ParseTree { | |
bool val; | |
public: | |
BoolConst(Token& t, bool val) : ParseTree(t.GetLinenum()), val(val) {} | |
NodeType GetType() const { return BOOLTYPE; } | |
}; | |
class SConst : public ParseTree { | |
string val; | |
public: | |
SConst(Token& t) : ParseTree(t.GetLinenum()) { | |
val = t.GetLexeme(); | |
} | |
NodeType GetType() const { return STRTYPE; } | |
}; | |
class Ident : public ParseTree { | |
string id; | |
public: | |
Ident(Token& t) : ParseTree(t.GetLinenum()), id(t.GetLexeme()) {} | |
}; | |
#endif /* PARSETREE_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
true; true; true; | |
"waffles"; | |
45; | |
327; | |
10312; | |
if 77 then true; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* projlex.h | |
* | |
* CS280 | |
* Spring 2018 | |
*/ | |
#ifndef TOKENS_H_ | |
#define TOKENS_H_ | |
#include <string> | |
#include <iostream> | |
using std::string; | |
using std::istream; | |
using std::ostream; | |
enum TokenType { | |
// keywords | |
PRINT, | |
IF, | |
THEN, | |
TRUE, | |
FALSE, | |
// an identifier | |
IDENT, | |
// an integer and string constant | |
ICONST, | |
SCONST, | |
// the operators, parens and semicolon | |
PLUS, | |
MINUS, | |
STAR, | |
SLASH, | |
ASSIGN, | |
EQ, | |
NEQ, | |
LT, | |
LEQ, | |
GT, | |
GEQ, | |
LOGICAND, | |
LOGICOR, | |
LPAREN, | |
RPAREN, | |
SC, | |
// any error returns this token | |
ERR, | |
// when completed (EOF), return this token | |
DONE | |
}; | |
class Token { | |
TokenType tt; | |
string lexeme; | |
int lnum; | |
public: | |
Token() { | |
tt = ERR; | |
lnum = -1; | |
} | |
Token(TokenType tt, string lexeme, int line) { | |
this->tt = tt; | |
this->lexeme = lexeme; | |
this->lnum = line; | |
} | |
bool operator==(const TokenType tt) const { return this->tt == tt; } | |
bool operator!=(const TokenType tt) const { return this->tt != tt; } | |
TokenType GetTokenType() const { return tt; } | |
string GetLexeme() const { return lexeme; } | |
int GetLinenum() const { return lnum; } | |
}; | |
extern ostream& operator<<(ostream& out, const Token& tok); | |
extern Token getNextToken(istream *in, int *linenum); | |
#endif /* TOKENS_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment