CMSC 430
listing.cc
listing.cc
// CMSC 430 Compiler Theory and Design
// Project 4 Skeleton
// UMGC CITE
// Summer 2023
// This file contains the bodies of the functions that produces the
// compilation listing
#include
<
cstdio
>
#include
<
string
>
#include
<
vector
>
using
namespace
std
;
#include
"listing.h"
static
int
lineNumber
;
static
int
lexicalErrors
;
static
int
syntaxErrors
;
static
int
semanticErrors
;
static
vector
<
string
>
errors
;
static
void
displayErrors
();
void
firstLine
()
{
lexicalErrors
=
0
;
syntaxErrors
=
0
;
semanticErrors
=
0
;
lineNumber
=
1
;
printf
(
"\n%4d "
,
lineNumber
);
}
void
nextLine
()
{
displayErrors
();
lineNumber
++
;
printf
(
"%4d "
,
lineNumber
);
}
int
lastLine
()
{
printf
(
"\r"
);
displayErrors
();
printf
(
" \n"
);
int
totalErrors
=
lexicalErrors
+
syntaxErrors
+
semanticErrors
;
if
(
totalErrors
>
0
)
{
printf
(
"Lexical Errors %d\n"
,
lexicalErrors
);
printf
(
"Syntax Errors %d\n"
,
syntaxErrors
);
printf
(
"Semantic Errors %d\n"
,
semanticErrors
);
}
else
printf
(
"Compiled Successfully\n\n"
);
return
totalErrors
;
}
void
appendError
(
ErrorCategories
errorCategory
,
string message
)
{
string messages
[]
=
{
"Lexical Error, Invalid Character "
,
"Syntax Error, U"
,
"Semantic Error, "
,
"Semantic Error, Duplicate "
,
"Semantic Error, Undeclared "
};
switch
(
errorCategory
)
{
case
LEXICAL
:
lexicalErrors
++
;
break
;
case
SYNTAX
:
message
=
message
.
substr
(
15
);
syntaxErrors
++
;
break
;
case
GENERAL_SEMANTIC
:
case
DUPLICATE_IDENTIFIER
:
case
UNDECLARED
:
semanticErrors
++
;
break
;
}
errors
.
push_back
(
messages
[
errorCategory
]
+
message
);
}
void
displayErrors
()
{
for
(
int
i
=
0
;
i
<
errors
.
size
();
i
++
)
printf
(
"%s\n"
,
errors
[
i
].
c_str
());
errors
.
clear
();
}
listing.h
// CMSC 430 Compiler Theory and Design // Project 4 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 types.o g++ -o compile scanner.o parser.o listing.o types.o scanner.o: scanner.c types.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 types.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 types.o: types.cc types.h g++ -c types.cc
parser.y
/* CMSC 430 Compiler Theory and Design Project 4 Skeleton UMGC CITE Summer 2023 Project 4 Parser with semantic actions for static semantic errors */ %{ #include <string> #include <vector> #include <map> using namespace std; #include "types.h" #include "listing.h" #include "symbols.h" int yylex(); Types find(Symbols<Types>& table, CharPtr identifier, string tableName); void yyerror(const char* message); Symbols<Types> scalars; Symbols<Types> lists; %} %define parse.error verbose %union { CharPtr iden; Types type; } %token <iden> IDENTIFIER %token <type> INT_LITERAL CHAR_LITERAL %token ADDOP MULOP RELOP ANDOP ARROW %token BEGIN_ CASE CHARACTER ELSE END ENDSWITCH FUNCTION INTEGER IS LIST OF OTHERS RETURNS SWITCH WHEN %type <type> list expressions body type statement_ statement cases case expression term primary %% function: function_header optional_variable body ; function_header: FUNCTION IDENTIFIER RETURNS type ';' ; type: INTEGER {$$ = INT_TYPE;} | CHARACTER {$$ = CHAR_TYPE; }; optional_variable: variable | %empty ; variable: IDENTIFIER ':' type IS statement ';' {checkAssignment($3, $5, "Variable Initialization"); scalars.insert($1, $3);} | IDENTIFIER ':' LIST OF type IS list ';' {lists.insert($1, $5);} ; list: '(' expressions ')' {$$ = $2;} ; expressions: expressions ',' expression | expression ; body: BEGIN_ statement_ END ';' {$$ = $2;} ; statement_: statement ';' | error ';' {$$ = MISMATCH;} ; statement: expression | WHEN condition ',' expression ':' expression {$$ = checkWhen($4, $6);} | SWITCH expression IS cases OTHERS ARROW statement ';' ENDSWITCH {$$ = checkSwitch($2, $4, $7);} ; cases: cases case {$$ = checkCases($1, $2);} | %empty {$$ = NONE;} ; case: CASE INT_LITERAL ARROW statement ';' {$$ = $4;} ; condition: condition ANDOP relation | relation ; relation: '(' condition')' | expression RELOP expression ; expression: expression ADDOP term {$$ = checkArithmetic($1, $3);} | term ; term: term MULOP primary {$$ = checkArithmetic($1, $3);} | primary ; primary: '(' expression ')' {$$ = $2;} | INT_LITERAL | CHAR_LITERAL | IDENTIFIER '(' expression ')' {$$ = find(lists, $1, "List");} | IDENTIFIER {$$ = find(scalars, $1, "Scalar");} ; %% Types find(Symbols<Types>& table, CharPtr identifier, string tableName) { Types type; if (!table.find(identifier, type)) { appendError(UNDECLARED, tableName + " " + identifier); return MISMATCH; } return type; } void yyerror(const char* message) { appendError(SYNTAX, message); } int main(int argc, char *argv[]) { firstLine(); yyparse(); lastLine(); return 0; }
scanner.l
/* CMSC 430 Compiler Theory and Design Project 4 Skeleton UMGC CITE Summer 2023 */ /* This file contains flex input file */ %{ #include <cstdio> #include <string> #include <vector> using namespace std; #include "types.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; return(ADDOP); } "*" { ECHO; return(MULOP); } "&" { ECHO; return(ANDOP); } "<" { ECHO; 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.type = INT_TYPE; return(INT_LITERAL); } {char} { ECHO; yylval.type = CHAR_TYPE; return(CHAR_LITERAL); } {punc} { ECHO; return(yytext[0]); } . { ECHO; appendError(LEXICAL, yytext); } %%
symbols.h
// CMSC 430 Compiler Theory and Design // Project 4 Skeleton // 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; }
types.cc
types.cc
// CMSC 430 Compiler Theory and Design
// Project 4 Skeleton
// UMGC CITE
// Summer 2023
// This file contains the bodies of the type checking functions
#include
<
string
>
#include
<
vector
>
using
namespace
std
;
#include
"types.h"
#include
"listing.h"
void
checkAssignment
(
Types
lValue
,
Types
rValue
,
string message
)
{
if
(
lValue
!=
MISMATCH
&&
rValue
!=
MISMATCH
&&
lValue
!=
rValue
)
appendError
(
GENERAL_SEMANTIC
,
"Type Mismatch on "
+
message
);
}
Types
checkWhen
(
Types
true_
,
Types
false_
)
{
if
(
true_
==
MISMATCH
||
false_
==
MISMATCH
)
return
MISMATCH
;
if
(
true_
!=
false_
)
appendError
(
GENERAL_SEMANTIC
,
"When Types Mismatch "
);
return
true_
;
}
Types
checkSwitch
(
Types
case_
,
Types
when
,
Types
other
)
{
if
(
case_
!=
INT_TYPE
)
appendError
(
GENERAL_SEMANTIC
,
"Switch Expression Not Integer"
);
return
checkCases
(
when
,
other
);
}
Types
checkCases
(
Types
left
,
Types
right
)
{
if
(
left
==
MISMATCH
||
right
==
MISMATCH
)
return
MISMATCH
;
if
(
left
==
NONE
||
left
==
right
)
return
right
;
appendError
(
GENERAL_SEMANTIC
,
"Case Types Mismatch"
);
return
MISMATCH
;
}
Types
checkArithmetic
(
Types
left
,
Types
right
)
{
if
(
left
==
MISMATCH
||
right
==
MISMATCH
)
return
MISMATCH
;
if
(
left
==
INT_TYPE
&&
right
==
INT_TYPE
)
return
INT_TYPE
;
appendError
(
GENERAL_SEMANTIC
,
"Integer Type Required"
);
return
MISMATCH
;
}
types.h
// CMSC 430 Compiler Theory and Design // Project 4 Skeleton // UMGC CITE // Summer 2023 // This file contains type definitions and the function // prototypes for the type checking functions typedef char* CharPtr; enum Types {MISMATCH, INT_TYPE, CHAR_TYPE, NONE}; void checkAssignment(Types lValue, Types rValue, string message); Types checkWhen(Types true_, Types false_); Types checkSwitch(Types case_, Types when, Types other); Types checkCases(Types left, Types right); Types checkArithmetic(Types left, Types right);