This server is intended for use for Academic Classwork related Git repositories only. Projects/repositories will generally be removed after 6 months following close of the semester. Inactive repositories from previous semester are now being archived when no activity for 365 days. They are renamed and marked as 'archived'. After 90 days in that state they will be removed from the system completely.

Commit c46d9a02 authored by Hogan's avatar Hogan

parser.y conflict

Merge branch 'master' of https://git-classes.mst.edu/jdev52/plants-hw4
parents 9cc798ae 99a9fea0
default: all
all: mfpl
all: evanshogan_parser
mfpl: lex.yy.c parser.tab.c
g++ parser.tab.c -o mfpl
evanshogan_parser: lex.yy.c evanshogan.tab.c
g++ evanshogan.tab.c -o evanshogan_parser
parser.tab.c: parser.y
bison parser.y
evanshogan.tab.c: evanshogan.y
bison evanshogan.y
lex.yy.c: lexer.l
flex lexer.l
lex.yy.c: evanshogan.l
flex evanshogan.l
clean:
-@rm -f lex.yy.c
-@rm -f parser.tab.c
-@rm -f mfpl
\ No newline at end of file
-@rm -f evanshogan.tab.c
-@rm -f evanshogan_parser
\ No newline at end of file
......@@ -17,15 +17,10 @@ using namespace std;
#define STR_OR_BOOL 6
#define INT_OR_STR_OR_BOOL 7
#define NOT_APPLICABLE -1
typedef struct
{
int type;
// one of the above type codes
int numParams;
// numParams and returnType only applicable if type == FUNCTION
int returnType;
} TYPE_INFO;
#define ARITHMETIC 10
#define LOGICAL 11
#define RELATIONAL 12
class SYMBOL_TABLE
{
......@@ -61,6 +56,16 @@ public:
else return(true);
}
SYMBOL_TABLE_ENTRY getEntry(string theName)
{
return hashTable.find(theName)->second;
}
int count()
{
return(hashTable.size());
}
};
#endif // SYMBOL_TABLE_H
......@@ -6,26 +6,53 @@ using namespace std;
#define UNDEFINED -1
typedef struct
{
// one of the above type codes
int type;
// numParams and returnType only applicable if type == FUNCTION
int numParams;
int returnType;
// operatorType is only applicable if production is an operator
int operatorType;
} TYPE_INFO;
class SYMBOL_TABLE_ENTRY
{
private:
// Member variables
string name;
int typeCode;
TYPE_INFO typeInfo;
public:
// Constructors
SYMBOL_TABLE_ENTRY( ) { name = ""; typeCode = UNDEFINED; }
SYMBOL_TABLE_ENTRY( ) {
name = "";
typeInfo.type = UNDEFINED;
typeInfo.numParams = UNDEFINED;
typeInfo.returnType = UNDEFINED;
}
SYMBOL_TABLE_ENTRY(const string theName, const TYPE_INFO theType) {
name = theName;
typeInfo.type = theType.type;
typeInfo.returnType = theType.returnType;
typeInfo.numParams = theType.numParams;
}
SYMBOL_TABLE_ENTRY(const string theName, const int theType)
{
SYMBOL_TABLE_ENTRY(const string theName, const int type = UNDEFINED,
const int numParams = UNDEFINED, const int returnType = UNDEFINED){
name = theName;
typeCode = theType;
typeInfo.type = type;
typeInfo.returnType = numParams;
typeInfo.numParams = returnType;
}
// Accessors
string getName() const { return name; }
int getTypeCode() const { return typeCode; }
TYPE_INFO getTypeInfo() const { return typeInfo; }
};
#endif // SYMBOL_TABLE_ENTRY_H
......@@ -23,7 +23,7 @@ test_files=`ls ./sample_input`
diff_files=0
for file in $test_files; do
mfpl < ./sample_input/$file > ./my_output/$file.out
./evanshogan_parser < ./sample_input/$file > ./my_output/$file.out
diff_lines=`diff ./my_output/$file.out \
./expected_output/$file.out \
......@@ -41,3 +41,4 @@ done
echo
echo "Number of different input files: $diff_files"
echo
make clean
......@@ -29,151 +29,124 @@ COMMENT ";".*
{COMMENT} {}
"let*" {
printToken("LETSTAR", yytext);
beginScope();
return T_LETSTAR;
}
"lambda" {
printToken("LAMBDA", yytext);
beginScope();
return T_LAMBDA;
}
"input" {
printToken("INPUT", yytext);
return T_INPUT;
}
"print" {
printToken("PRINT", yytext);
return T_PRINT;
}
"if" {
printToken("IF", yytext);
return T_IF;
}
"exit" {
printToken("EXIT", yytext);
return T_EXIT;
}
"progn" {
printToken("PROGN", yytext);
return T_PROGN;
}
"(" {
printToken("LPAREN", yytext);
return T_LPAREN;
}
")" {
printToken("RPAREN", yytext);
return T_RPAREN;
}
"+" {
printToken("ADD", yytext);
return T_ADD;
}
"*" {
printToken("MULT", yytext);
return T_MULT;
}
"/" {
printToken("DIV", yytext);
return T_DIV;
}
"-" {
printToken("SUB", yytext);
return T_SUB;
}
"and" {
printToken("AND", yytext);
return T_AND;
}
"or" {
printToken("OR", yytext);
return T_OR;
}
"not" {
printToken("NOT", yytext);
return T_NOT;
}
"<" {
printToken("LT", yytext);
return T_LT;
}
">" {
printToken("GT", yytext);
return T_GT;
}
"<=" {
printToken("LE", yytext);
return T_LE;
}
">=" {
printToken("GE", yytext);
return T_GE;
}
"=" {
printToken("EQ", yytext);
return T_EQ;
}
"/=" {
printToken("NE", yytext);
return T_NE;
}
"t" {
printToken("T", yytext);
return T_T;
}
"nil" {
printToken("NIL", yytext);
return T_NIL;
}
{IDENT} {
yylval.text = strdup(yytext);
printToken("IDENT", yytext);
return T_IDENT;
}
{INTCONST} {
printToken("INTCONST", yytext);
return T_INTCONST;
}
{STRCONST} {
printToken("STRCONST", yytext);
return T_STRCONST;
}
......@@ -184,7 +157,6 @@ COMMENT ";".*
{WSPACE} { }
. {
printToken("UNKNOWN", yytext);
return T_UNKNOWN;
}
%%
\ No newline at end of file
%{
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <stack>
#include "SymbolTable.h"
using namespace std;
stack<SYMBOL_TABLE> scopeStack; // stack of scope hashtables
void beginScope();
void endScope();
void cleanUp();
void prepareToTerminate();
void bail();
bool findEntryInAnyScope(const string theName);
SYMBOL_TABLE_ENTRY getEntryInAnyScope(const string theName);
void printToken(const char* tokenType, char* lexeme);
void printRule(const char*, const char*);
int yyerror(const char* s);
extern "C"
{
int yyparse(void);
int yylex(void);
int yywrap() {return 1;}
}
%}
%union
{
char* text;
TYPE_INFO typeInfo;
};
/*
* Token declarations
*/
%token T_LPAREN T_RPAREN
%token T_IF T_LETSTAR T_LAMBDA T_PRINT T_INPUT T_PROGN T_EXIT
%token T_ADD T_SUB T_MULT T_DIV
%token T_LT T_GT T_LE T_GE T_EQ T_NE T_AND T_OR T_NOT
%token T_INTCONST T_STRCONST T_T T_NIL T_IDENT T_UNKNOWN
/*
* Type Identifications
*/
%type <text> T_IDENT
%type <typeInfo> N_START N_EXPR N_CONST N_PARENTHESIZED_EXPR
%type <typeInfo> N_PROGN_OR_USERFUNCTCALL N_ACTUAL_PARAMS N_FUNCT_NAME
%type <typeInfo> N_ARITHLOGIC_EXPR N_IF_EXPR N_LET_EXPR N_ID_EXPR_LIST
%type <typeInfo> N_LAMBDA_EXPR N_ID_LIST N_PRINT_EXPR N_INPUT_EXPR
%type <typeInfo> N_EXPR_LIST N_BIN_OP N_ARITH_OP N_REL_OP N_LOG_OP N_UN_OP
/*
* Starting point.
*/
%start N_START
/*
* Translation rules.
*/
%%
N_START : // epsilon
{
}
| N_START N_EXPR
{
/*
cout << "EXPR type is: ";
switch ($2.type){
case 1:
cout<<"INT"<<"\n";
break;
case 2:
cout<<"STR"<<"\n";
break;
case 4:
cout<<"BOOL"<<"\n";
break;
case 8:
cout<<"FUNCTION"<<"\n";
break;
case 3:
cout<<"INT_OR_STR"<<"\n";
break;
case 5:
cout<<"INT_OR_BOOL"<<"\n";
break;
case 6:
cout<<"STR_OR_BOOL"<<"\n";
break;
case 7:
cout<<"INT_OR_STR_OR_BOOL"<<"\n";
break;
}
*/
cout << "\nValue of the expression is: \n";
cout << "---- Completed parsing ----\n" << endl;
}
;
N_EXPR : N_CONST
{
//resulting type is the type of N_CONST
$$.type=$1.type;
$$.numParams=NOT_APPLICABLE;
$$.returnType=NOT_APPLICABLE;
}
| T_IDENT
{
string lexeme = string($1);
if(!findEntryInAnyScope(lexeme)){
yyerror("Undefined identifier");
}
//resulting type is the type of the identifier
//look up in the symbol table
$$.type = getEntryInAnyScope(lexeme).getTypeInfo().type;
}
| T_LPAREN N_PARENTHESIZED_EXPR T_RPAREN
{
//resulting type is the resulting type of the parenthesized expr
$$.type=$2.type;
$$.numParams=$2.numParams;
$$.returnType=$2.returnType;
}
;
N_CONST : T_INTCONST
{
//type is int
$$.type=INT;
$$.numParams=NOT_APPLICABLE;
$$.returnType=NOT_APPLICABLE;
}
| T_STRCONST
{
//type is string
$$.type=STR;
$$.numParams=NOT_APPLICABLE;
$$.returnType=NOT_APPLICABLE;
}
| T_T
{
//type is bool
$$.type=BOOL;
$$.numParams=NOT_APPLICABLE;
$$.returnType=NOT_APPLICABLE;
}
| T_NIL
{
//type is bool
$$.type=BOOL;
$$.numParams=NOT_APPLICABLE;
$$.returnType=NOT_APPLICABLE;
}
;
N_PARENTHESIZED_EXPR : N_ARITHLOGIC_EXPR
//resulting type of whatever rule is applied
{
$$.type=$1.type;
$$.numParams=$1.numParams;
$$.returnType=$1.returnType;
}
| N_IF_EXPR
{
$$.type=$1.type;
$$.numParams=$1.numParams;
$$.returnType=$1.returnType;
}
| N_LET_EXPR
{
$$.type=$1.type;
$$.numParams=$1.numParams;
$$.returnType=$1.returnType;
}
| N_LAMBDA_EXPR
{
$$.type=$1.type;
$$.numParams=$1.numParams;
$$.returnType=$1.returnType;
}
| N_PRINT_EXPR
{
$$.type=$1.type;
$$.numParams=$1.numParams;
$$.returnType=$1.returnType;
}
| N_INPUT_EXPR
{
$$.type=$1.type;
$$.numParams=$1.numParams;
$$.returnType=$1.returnType;
}
| N_PROGN_OR_USERFUNCTCALL
{
$$.type=$1.type;
$$.numParams=$1.numParams;
$$.returnType=$1.returnType;
}
| T_EXIT
{
bail();
}
;
N_PROGN_OR_USERFUNCTCALL : N_FUNCT_NAME N_ACTUAL_PARAMS
{
if($1.type == UNDEFINED){
if($2.type == NOT_APPLICABLE){
$$.type = BOOL;
} else {
$$.type = $2.type;
}
} else {
if($1.numParams < $2.numParams){
yyerror("Too many parameters in function call");
} else if($1.numParams < $2.numParams){
yyerror("Too few parameters in function call");
}
$$.type = $1.type;
}
$$.numParams = $2.numParams;
$$.returnType = UNDEFINED;
}
| T_LPAREN N_LAMBDA_EXPR T_RPAREN N_ACTUAL_PARAMS
{
if($2.numParams < $4.numParams){
yyerror("Too many parameters in function call");
} else if($4.numParams < $2.numParams){
yyerror("Too few parameters in function call");
}
$$.type = $2.returnType;
$$.numParams = $4.numParams;
$$.returnType = $2.returnType;
}
;
N_ACTUAL_PARAMS : N_EXPR_LIST
{
$$.type = $1.type;
$$.numParams = $1.numParams;
$$.returnType = $1.type;
}
| /*epsilon*/
{
$$.type = NOT_APPLICABLE;
$$.numParams = 0;
$$.returnType = NOT_APPLICABLE;
}
N_FUNCT_NAME : T_PROGN
{
$$.type = UNDEFINED;
$$.numParams = 0;
$$.returnType = UNDEFINED;
}
| T_IDENT
{
string lexeme = string($1);
if(!findEntryInAnyScope(lexeme)){
yyerror("Undefined identifier");
}
TYPE_INFO typeInfo = getEntryInAnyScope(lexeme).getTypeInfo();
if(typeInfo.type != FUNCTION){
yyerror("Arg 1 must be a function");
}
$$.type = typeInfo.returnType;
$$.numParams = typeInfo.numParams;
$$.returnType = typeInfo.returnType;
}
;
N_ARITHLOGIC_EXPR : N_UN_OP N_EXPR
{
if($2.type == FUNCTION){
yyerror("Arg 1 cannot be a function");
}
$$.type = BOOL;
$$.numParams = NOT_APPLICABLE;
$$.returnType = NOT_APPLICABLE;
}
| N_BIN_OP N_EXPR N_EXPR
{
//check if operation can be preformed
switch($1.operatorType){
case RELATIONAL:
if(($2.type != INT) && ($2.type != STR)){
yyerror("Arg 1 must be integer or string");
}
if(($3.type != INT) && ($3.type != STR)){
yyerror("Arg 2 must be integer or string");
}
if(($2.type == INT) && (($3.type != INT) && ($3.type != INT_OR_STR))){
yyerror("Arg 2 must be integer");
}
if(($2.type == STR) && (($3.type != STR) && ($3.type != INT_OR_STR))){
yyerror("Arg 2 must be string");
}
break;
case LOGICAL:
if($2.type == FUNCTION) {
yyerror("Arg 1 cannot be a function");
}
if($3.type == FUNCTION) {
yyerror("Arg 2 cannot be a function");
}
break;
case ARITHMETIC:
switch($2.type){
case INT:
case INT_OR_STR:
case INT_OR_BOOL:
case INT_OR_STR_OR_BOOL:
break;
default:
yyerror("Arg 1 must be integer");
break;
}
switch($3.type){
case INT:
case INT_OR_STR:
case INT_OR_BOOL:
case INT_OR_STR_OR_BOOL:
break;
</