430 CMSC
listing.cc
listing.cc
// CMSC 430 Compiler Theory and Design
// Project 3 Skeleton
// UMGC CITE
// Summer 2023
// This file contains the bodies of the functions that produces the
// compilation listing
#include
<
cstdio
>
#include
<
string
>
using
namespace
std
;
#include
"listing.h"
static
int
lineNumber
;
static
string error
=
""
;
static
int
totalErrors
=
0
;
static
void
displayErrors
();
void
firstLine
()
{
lineNumber
=
1
;
printf
(
"\n%4d "
,
lineNumber
);
}
void
nextLine
()
{
displayErrors
();
lineNumber
++
;
printf
(
"%4d "
,
lineNumber
);
}
int
lastLine
()
{
printf
(
"\r"
);
displayErrors
();
printf
(
" \n"
);
return
totalErrors
;
}
void
appendError
(
ErrorCategories
errorCategory
,
string message
)
{
string messages
[]
=
{
"Lexical Error, Invalid Character "
,
""
,
"Semantic Error, "
,
"Semantic Error, Duplicate "
,
"Semantic Error, Undeclared "
};
error
=
messages
[
errorCategory
]
+
message
;
totalErrors
++
;
}
void
displayErrors
()
{
if
(
error
!=
""
)
printf
(
"%s\n"
,
error
.
c_str
());
error
=
""
;
}
listing.h
// CMSC 430 Compiler Theory and Design // Project 3 Skeleton // UMGC CITE // Summer 2023 // This file contains the function prototypes for the functions that produce // the compilation listing enum ErrorCategories {LEXICAL, SYNTAX, GENERAL_SEMANTIC, DUPLICATE_IDENTIFIER, UNDECLARED}; void firstLine(); void nextLine(); int lastLine(); void appendError(ErrorCategories errorCategory, string message);
makefile
compile: scanner.o parser.o listing.o values.o g++ -o compile scanner.o parser.o listing.o values.o scanner.o: scanner.c values.h listing.h tokens.h g++ -c scanner.c scanner.c: scanner.l flex scanner.l mv lex.yy.c scanner.c parser.o: parser.c values.h listing.h symbols.h g++ -c parser.c parser.c tokens.h: parser.y bison -d -v parser.y mv parser.tab.c parser.c cp parser.tab.h tokens.h listing.o: listing.cc listing.h g++ -c listing.cc values.o: values.cc values.h g++ -c values.cc
parser.y
/* CMSC 430 Compiler Theory and Design Project 3 Skeleton UMGC CITE Summer 2023 Project 3 Parser with semantic actions for the interpreter */ %{ #include <iostream> #include <cmath> #include <string> #include <vector> #include <map> using namespace std; #include "values.h" #include "listing.h" #include "symbols.h" int yylex(); void yyerror(const char* message); double extract_element(CharPtr list_name, double subscript); Symbols<double> scalars; Symbols<vector<double>*> lists; double result; %} %define parse.error verbose %union { CharPtr iden; Operators oper; double value; vector<double>* list; } %token <iden> IDENTIFIER %token <value> INT_LITERAL CHAR_LITERAL %token <oper> ADDOP MULOP ANDOP RELOP %token ARROW %token BEGIN_ CASE CHARACTER ELSE END ENDSWITCH FUNCTION INTEGER IS LIST OF OTHERS RETURNS SWITCH WHEN %type <value> body statement_ statement cases case expression term primary condition relation %type <list> list expressions %% function: function_header optional_variable body ';' {result = $3;} ; function_header: FUNCTION IDENTIFIER RETURNS type ';' ; type: INTEGER | CHARACTER ; optional_variable: variable | %empty ; variable: IDENTIFIER ':' type IS statement ';' {scalars.insert($1, $5);}; | IDENTIFIER ':' LIST OF type IS list ';' {lists.insert($1, $7);} ; list: '(' expressions ')' {$$ = $2;} ; expressions: expressions ',' expression {$1->push_back($3); $$ = $1;} | expression {$$ = new vector<double>(); $$->push_back($1);} body: BEGIN_ statement_ END {$$ = $2;} ; statement_: statement ';' | error ';' {$$ = 0;} ; statement: expression | WHEN condition ',' expression ':' expression {$$ = $2 ? $4 : $6;} | SWITCH expression IS cases OTHERS ARROW statement ';' ENDSWITCH {$$ = !isnan($4) ? $4 : $7;} ; cases: cases case {$$ = !isnan($1) ? $1 : $2;} | %empty {$$ = NAN;} ; case: CASE INT_LITERAL ARROW statement ';' {$$ = $<value>-2 == $2 ? $4 : NAN;} ; condition: condition ANDOP relation {$$ = $1 && $2;} | relation ; relation: '(' condition ')' {$$ = $2;} | expression RELOP expression {$$ = evaluateRelational($1, $2, $3);} ; expression: expression ADDOP term {$$ = evaluateArithmetic($1, $2, $3);} | term ; term: term MULOP primary {$$ = evaluateArithmetic($1, $2, $3);} | primary ; primary: '(' expression ')' {$$ = $2;} | INT_LITERAL | CHAR_LITERAL | IDENTIFIER '(' expression ')' {$$ = extract_element($1, $3); } | IDENTIFIER {if (!scalars.find($1, $$)) appendError(UNDECLARED, $1);} ; %% void yyerror(const char* message) { appendError(SYNTAX, message); } double extract_element(CharPtr list_name, double subscript) { vector<double>* list; if (lists.find(list_name, list)) return (*list)[subscript]; appendError(UNDECLARED, list_name); return NAN; } int main(int argc, char *argv[]) { firstLine(); yyparse(); if (lastLine() == 0) cout << "Result = " << result << endl; return 0; }
scanner.l
/* CMSC 430 Compiler Theory and Design Project 3 Skeleton UMGC CITE Summer 2023 */ /* This file contains flex input file */ %{ #include <cstdio> #include <string> #include <vector> using namespace std; #include "values.h" #include "listing.h" #include "tokens.h" %} %option noyywrap ws [ \t\r]+ comment "//".*\n line [\n] id [A-Za-z]([A-Za-z0-9])* digit [0-9] dec {digit}+ char '.' punc [\(\),:;] %% {ws} { ECHO; } {comment} { ECHO; nextLine(); } {line} { ECHO; nextLine(); } "+" { ECHO; yylval.oper = ADD; return(ADDOP); } "*" { ECHO; yylval.oper = MULTIPLY; return(MULOP); } "&" { ECHO; yylval.oper = AND; return(ANDOP); } "<" { ECHO; yylval.oper = LESS; return(RELOP); } "=>" { ECHO; return(ARROW); } begin { ECHO; return(BEGIN_); } case { ECHO; return(CASE); } character { ECHO; return(CHARACTER); } end { ECHO; return(END); } endswitch { ECHO; return(ENDSWITCH); } function { ECHO; return(FUNCTION); } integer { ECHO; return(INTEGER); } is { ECHO; return(IS); } list { ECHO; return(LIST); } of { ECHO; return(OF); } others { ECHO; return(OTHERS); } returns { ECHO; return(RETURNS); } switch { ECHO; return(SWITCH); } when { ECHO; return(WHEN); } {id} { ECHO; yylval.iden = (CharPtr)malloc(yyleng + 1); strcpy(yylval.iden, yytext); return(IDENTIFIER);} {dec} { ECHO; yylval.value = atoi(yytext); return(INT_LITERAL); } {char} { ECHO; yylval.value = yytext[1]; return(CHAR_LITERAL); } {punc} { ECHO; return(yytext[0]); } . { ECHO; appendError(LEXICAL, yytext); } %%
symbols.h
// CMSC 430 Compiler Theory and Design // Project 3 Complete // UMGC CITE // Summer 2023 // This file contains the template symbol table template <typename T> class Symbols { public: void insert(char* lexeme, T entry); bool find(char* lexeme, T& entry); private: map<string, T> symbols; }; template <typename T> void Symbols<T>::insert(char* lexeme, T entry) { string name(lexeme); symbols[name] = entry; } template <typename T> bool Symbols<T>::find(char* lexeme, T& entry) { string name(lexeme); typedef typename map<string, T>::iterator Iterator; Iterator iterator = symbols.find(name); bool found = iterator != symbols.end(); if (found) entry = iterator->second; return found; }
values.cc
values.cc
// CMSC 430 Compiler Theory and Design
// Project 3 Skeleton
// UMGC CITE
// Summer 2023
// This file contains the bodies of the evaluation functions
#include
<
string
>
#include
<
cmath
>
using
namespace
std
;
#include
"values.h"
#include
"listing.h"
double
evaluateArithmetic
(
double
left
,
Operators
operator_
,
double
right
)
{
double
result
;
switch
(
operator_
)
{
case
ADD
:
result
=
left
+
right
;
break
;
case
MULTIPLY
:
result
=
left
*
right
;
break
;
}
return
result
;
}
double
evaluateRelational
(
double
left
,
Operators
operator_
,
double
right
)
{
double
result
;
switch
(
operator_
)
{
case
LESS
:
result
=
left
<
right
;
break
;
}
return
result
;
}
values.h
// CMSC 430 Compiler Theory and Design // Project 3 Skeleton // UMGC CITE // Summer 2023 // This file contains type definitions and the function // definitions for the evaluation functions typedef char* CharPtr; enum Operators {ADD, MULTIPLY, LESS, AND}; double evaluateArithmetic(double left, Operators operator_, double right); double evaluateRelational(double left, Operators operator_, double right);