Compiler Theory

profilelily33
CMSC430P3.zip

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 >
#include   < vector >


using   namespace  std ;

#include   "listing.h"

static   int  lineNumber ;
static  string error  =   "" ;
static   int  totalErrors  =   0 ;
static   int  lexicalErrors  =   0 ;  
static   int  syntaxErrors  =   0 ;
static   int  semanticErrors  =   0 ;
static  vector < string >  errors ;

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" );

     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" );
     }

     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 ++ ;

     if   ( errorCategory  ==  LEXICAL )   {
        lexicalErrors ++ ;
     }   else   if   ( errorCategory  ==  SYNTAX )   {
        syntaxErrors ++ ;
     }   else   if   ( errorCategory  ==  GENERAL_SEMANTIC  ||  errorCategory  ==  DUPLICATE_IDENTIFIER  ||  errorCategory  ==  UNDECLARED )   {
        semanticErrors ++ ;
     }

    errors . push_back ( error );
    error  =   "" ;
}

void  displayErrors ()
{
     for   ( const  string  & err  :  errors )   {
        printf ( "%s\n" ,  err . c_str ());
     }
    errors . clear ();
}

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, ARITHMETIC, RELATIONAL}; 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 UMGC CITE 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; double* param_values; int param_index; %} %define parse.error verbose %union { CharPtr iden; Operators oper; double value; vector<double>* list; } %left ADDOP %left MULOP %right EXPOP %left ANDOP %left OROP %left RELOP %nonassoc NOTOP %token <iden> IDENTIFIER %token <value> INT_LITERAL CHAR_LITERAL REAL_LITERAL HEX_LITERAL %token <oper> ADDOP MULOP ANDOP RELOP ARROW OROP MODOP EXPOP NOTOP NEGOP SUBOP DIVOP %token BEGIN_ CASE CHARACTER IF ELSE END ENDSWITCH FUNCTION INTEGER IS LIST OF OTHERS RETURNS SWITCH WHEN ELSIF THEN ENDIF FOLD ENDFOLD LEFT RIGHT REAL %type <value> function function_header type optional_variable variables variable body statement_ statement cases case condition relation expression term factor unary primary optional_parameters parameters parameter elsif_statements else_statement direction operator others_case %type <list> list expressions list_choice %% function: function_header optional_variable body ';' {result = $3;}; function_header: FUNCTION IDENTIFIER optional_parameters RETURNS type ';' { param_index = 0; } | FUNCTION error ';' { $$ = 0; }; optional_parameters: %empty { $$ = 0; } | parameters; parameters: parameters ',' parameter { $$ = 0; } | parameter { $$ = 0; }; parameter: IDENTIFIER ':' type { scalars.insert($1, param_values[param_index++]); }; type: INTEGER { $$ = 0; } | REAL { $$ = 0; } | CHARACTER { $$ = 0; }; optional_variable: variables { $$ = 0; } | %empty { $$ = 0; }; variables: variables variable { $$ = 0; } | variable { $$ = 0; } | error ';' { $$ = 0; }; variable: IDENTIFIER ':' type IS statement ';' { scalars.insert($1, $5); $$ = 0; } | IDENTIFIER ':' LIST OF type IS list ';' { lists.insert($1, $7); $$ = 0; }; 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 ';' { $$ = $1; } | error ';' { $$ = 0; }; statement: expression { $$ = $1; } | WHEN condition ',' expression ':' expression { $$ = $2 ? $4 : $6; } | SWITCH expression IS cases others_case ENDSWITCH { $$ = !isnan($4) ? $4 : $5; } | IF condition THEN statement_ elsif_statements else_statement ENDIF { $$ = $2 ? $4 : ($5 != 0 ? $5 : $6); } | FOLD direction operator list_choice ENDFOLD { $$ = evaluateFold($2, (Operators)$3, $4); }; elsif_statements: %empty { $$ = 0; } | elsif_statements ELSIF condition THEN statement_ { $$ = $3 ? $5 : $1; }; else_statement: ELSE statement_ { $$ = $2; } | %empty { $$ = 0; }; cases: cases case { $$ = !isnan($1) ? $1 : $2; } | %empty { $$ = NAN; }; others_case: OTHERS ARROW statement ';' { $$ = $3; } | OTHERS ARROW statement { $$ = $2; } case: CASE INT_LITERAL ARROW statement ';' { $$ = ($2 == result) ? $4 : NAN; } | CASE CHAR_LITERAL ARROW statement ';' { $$ = ($2 == result) ? $4 : NAN; } | error ';' { $$ = NAN; }; direction: LEFT { $$ = 'L'; } | RIGHT { $$ = 'R'; }; operator: ADDOP { $$ = ADD; } | MULOP { $$ = MULTIPLY; } | SUBOP { $$ = SUBTRACT; } | DIVOP { $$ = DIVIDE; }; list_choice: list { $$ = $1; } | IDENTIFIER { vector<double>* temp; if (lists.find($1, temp)) $$ = temp; else { $$ = nullptr; appendError(UNDECLARED, $1); } }; condition: condition OROP relation { $$ = $1 || $3; } | condition ANDOP relation { $$ = $1 && $3; } | relation; relation: '(' condition ')' { $$ = $2; } | expression RELOP expression { $$ = evaluateRelational($1, $2, $3); } | NOTOP relation { $$ = !$2; }; expression: expression ADDOP term { $$ = evaluateArithmetic($1, $2, $3); } | expression SUBOP term { $$ = evaluateArithmetic($1, SUBTRACT, $3); } | term; term: term MULOP factor { $$ = evaluateArithmetic($1, $2, $3); } | term DIVOP factor { $$ = evaluateArithmetic($1, DIVIDE, $3); } | term MODOP factor { $$ = fmod($1, $3); } | factor; factor: primary EXPOP factor { $$ = pow($1, $3); } | unary; unary: NEGOP unary { $$ = -$2; } | primary; primary: '(' expression ')' { $$ = $2; } | INT_LITERAL { $$ = $1; } | REAL_LITERAL { $$ = $1; } | CHAR_LITERAL { $$ = $1; } | HEX_LITERAL { $$ = $1; } | 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(); param_values = new double[argc - 1]; for (int i = 1; i < argc; ++i) { param_values[i - 1] = atof(argv[i]); } yyparse(); if (lastLine() == 0) cout << "Result = " << result << endl; delete[] param_values; return 0; }

scanner.l

%{ #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <vector> using namespace std; #include "values.h" #include "listing.h" #include "tokens.h" %} %option noyywrap ws [ \t\r]+ comment "//".*\n newcomment "--".*\n line [\n] id [A-Za-z]([A-Za-z0-9]*(_{1,2}[A-Za-z0-9]+)*)* digit [0-9] hex [0-9A-Fa-f]+ dec {digit}+ real {digit}*"."{digit}+([eE][+-]?{digit}+)? hexint "#"{hex} char \'.\'|\'\\[btnfr]\' punc [\(\),:;] %% {ws} { ECHO; } {comment} { ECHO; nextLine(); } {newcomment} { ECHO; nextLine(); } {line} { ECHO; nextLine(); } "+" { ECHO; yylval.oper = ADD; return(ADDOP); } "-" { ECHO; yylval.oper = SUBTRACT; return(SUBOP); } "*" { ECHO; yylval.oper = MULTIPLY; return(MULOP); } "/" { ECHO; yylval.oper = DIVIDE; return(DIVOP); } "%" { ECHO; yylval.oper = MOD; return(MODOP); } "^" { ECHO; yylval.oper = EXPONENT; return(EXPOP); } "~" { ECHO; return(NEGOP); } "&" { ECHO; yylval.oper = AND; return(ANDOP); } "<" { ECHO; yylval.oper = LESS; return(RELOP); } "=>" { ECHO; return(ARROW); } "|" { ECHO; return(OROP); } "!" { ECHO; return(NOTOP); } "=" { ECHO; yylval.oper = EQUAL; return(RELOP); } "<>" { ECHO; yylval.oper = NOTEQUAL; return(RELOP); } ">" { ECHO; yylval.oper = GREATER; return(RELOP); } ">=" { ECHO; yylval.oper = GREATEREQUAL; return(RELOP); } "<=" { ECHO; yylval.oper = LESSEQUAL; return(RELOP); } 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); } else { ECHO; return(ELSE); } endif { ECHO; return(ENDIF); } endfold { ECHO; return(ENDFOLD); } elsif { ECHO; return(ELSIF); } fold { ECHO; return(FOLD); } if { ECHO; return(IF); } left { ECHO; return(LEFT); } real { ECHO; return(REAL); } right { ECHO; return(RIGHT); } then { ECHO; return(THEN); } {id} { ECHO; yylval.iden = strdup(yytext); return(IDENTIFIER); } {dec} { ECHO; yylval.value = atoi(yytext); return(INT_LITERAL); } {hexint} { ECHO; yylval.value = strtol(yytext + 1, nullptr, 16); return HEX_LITERAL; } {real} { ECHO; yylval.value = atof(yytext); return REAL_LITERAL; } {char} { if (strlen(yytext) == 3) { yylval.value = yytext[1]; } else { switch (yytext[2]) { case 'n': yylval.value = '\n'; break; case 't': yylval.value = '\t'; break; case 'r': yylval.value = '\r'; break; case 'f': yylval.value = '\f'; break; case 'b': yylval.value = '\b'; break; default: yylval.value = yytext[2]; break; } } 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; }

tokens.h

/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ #ifndef YY_YY_PARSER_TAB_H_INCLUDED # define YY_YY_PARSER_TAB_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ IDENTIFIER = 258, /* IDENTIFIER */ INT_LITERAL = 259, /* INT_LITERAL */ CHAR_LITERAL = 260, /* CHAR_LITERAL */ REAL_LITERAL = 261, /* REAL_LITERAL */ HEX_LITERAL = 262, /* HEX_LITERAL */ ADDOP = 263, /* ADDOP */ MULOP = 264, /* MULOP */ ANDOP = 265, /* ANDOP */ RELOP = 266, /* RELOP */ ARROW = 267, /* ARROW */ OROP = 268, /* OROP */ MODOP = 269, /* MODOP */ EXPOP = 270, /* EXPOP */ NOTOP = 271, /* NOTOP */ NEGOP = 272, /* NEGOP */ SUBOP = 273, /* SUBOP */ DIVOP = 274, /* DIVOP */ BEGIN_ = 275, /* BEGIN_ */ CASE = 276, /* CASE */ CHARACTER = 277, /* CHARACTER */ IF = 278, /* IF */ ELSE = 279, /* ELSE */ END = 280, /* END */ ENDSWITCH = 281, /* ENDSWITCH */ FUNCTION = 282, /* FUNCTION */ INTEGER = 283, /* INTEGER */ IS = 284, /* IS */ LIST = 285, /* LIST */ OF = 286, /* OF */ OTHERS = 287, /* OTHERS */ RETURNS = 288, /* RETURNS */ SWITCH = 289, /* SWITCH */ WHEN = 290, /* WHEN */ ELSIF = 291, /* ELSIF */ THEN = 292, /* THEN */ ENDIF = 293, /* ENDIF */ FOLD = 294, /* FOLD */ ENDFOLD = 295, /* ENDFOLD */ LEFT = 296, /* LEFT */ RIGHT = 297, /* RIGHT */ REAL = 298 /* REAL */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 35 "parser.y" CharPtr iden; Operators oper; double value; vector<double>* list; #line 114 "parser.tab.h" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE yylval; int yyparse (void); #endif /* !YY_YY_PARSER_TAB_H_INCLUDED */

values.cc

#include <iostream> #include <cmath> #include <vector> 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; case SUBTRACT: result = left - right; break; case DIVIDE: result = left / right; break; case MOD: result = fmod(left, right); break; case EXPONENT: result = pow(left, right); break; default: appendError(ARITHMETIC, "Unknown operator"); result = NAN; } return result; } double evaluateRelational(double left, Operators operator_, double right) { double result; switch (operator_) { case LESS: result = left < right; break; case GREATER: result = left > right; break; case EQUAL: result = left == right; break; case NOTEQUAL: result = left != right; break; case LESSEQUAL: result = left <= right; break; case GREATEREQUAL: result = left >= right; break; default: appendError(RELATIONAL, "Unknown operator"); result = NAN; } return result; } double evaluateFold(char direction, Operators oper, vector<double>* list) { if (!list || list->empty()) { appendError(GENERAL_SEMANTIC, "Empty list in fold operation"); return NAN; } double result; if (direction == 'L') { result = list->front(); for (size_t i = 1; i < list->size(); ++i) { result = evaluateArithmetic(result, oper, (*list)[i]); } } else { result = list->back(); for (int i = list->size() - 2; i >= 0; --i) { result = evaluateArithmetic((*list)[i], oper, result); } } 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, SUBTRACT, DIVIDE, MOD, EXPONENT, LESS, GREATER, EQUAL, NOTEQUAL, LESSEQUAL, GREATEREQUAL, AND, OR, NOT }; double evaluateArithmetic(double left, Operators operator_, double right); double evaluateRelational(double left, Operators operator_, double right); double evaluateFold(char direction, Operators oper, std::vector<double>* list);