diff --git a/recursiveDescentParsers/cplusplus/interpreter/.gitignore b/recursiveDescentParsers/cplusplus/interpreter/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..dd56fba1f7d6b29681d74e8c2ac55afc270dc52b --- /dev/null +++ b/recursiveDescentParsers/cplusplus/interpreter/.gitignore @@ -0,0 +1,3 @@ +interpreter +tmp.txt + diff --git a/recursiveDescentParsers/cplusplus/interpreter/Makefile b/recursiveDescentParsers/cplusplus/interpreter/Makefile index fd54984efa8f29c2ddfa4be5b66f752ceeb96c72..f41bbbcabdec7d4c41c9818ea1c74078aecb8ac2 100644 --- a/recursiveDescentParsers/cplusplus/interpreter/Makefile +++ b/recursiveDescentParsers/cplusplus/interpreter/Makefile @@ -6,7 +6,7 @@ PROGS := interpreter - +TESTFILES := testInput.txt testOutput.txt # Uncomment only one of the next two lines (choose your c++ compiler) # CC=g++ CC := clang++ @@ -22,7 +22,7 @@ CFLAGS := # Tell make that the following "targets" are "phony" # Cf. https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html#Phony-Targets -.PHONY : all clean +.PHONY : all clean test ## Now, the targets -- the things that will get made! @@ -32,5 +32,12 @@ $(PROGS): %: %.cpp $(CC) -g $< $(CFLAGS) -o $@ clean: - $(RM) -fv *~ *.o $(PROGS) + $(RM) -v *~ *.o $(PROGS) tmp.txt + +test: $(PROGS) $(TESTFILES) + # "Running interpreter in test mode\n" + -./interpreter testInput.txt 2>&1 >tmp.txt + # "Checking output -- no news is good news!\n" + diff testOutput.txt tmp.txt + -rm tmp.txt diff --git a/recursiveDescentParsers/cplusplus/interpreter/interpreter b/recursiveDescentParsers/cplusplus/interpreter/interpreter deleted file mode 100755 index 066ac63171237fe93a4d8312b1af2aa713881b14..0000000000000000000000000000000000000000 Binary files a/recursiveDescentParsers/cplusplus/interpreter/interpreter and /dev/null differ diff --git a/recursiveDescentParsers/cplusplus/interpreter/interpreter.cpp b/recursiveDescentParsers/cplusplus/interpreter/interpreter.cpp index 5996dd5844aad6e7105d34e19e394bfc535034c0..c481e21910b2a1b85ad5d2b14a10fe9f729df087 100644 --- a/recursiveDescentParsers/cplusplus/interpreter/interpreter.cpp +++ b/recursiveDescentParsers/cplusplus/interpreter/interpreter.cpp @@ -48,6 +48,17 @@ static int currentTokenLength = 0; static Token next_token; // again with the global variables... static numberType currentNumber; // = zero.... +static void printErrorMsg( const std::string Error ) +{ + std::cout << "ERROR on line " << currentLineNumber + << ", column " << currentColumnNumber << " : " + << Error << std::endl; + std::cout << currentLine; + for ( int col = 0; col < currentColumnNumber-1; col++ ) + std::cout << '-'; + std::cout << '^' << std::endl; +} // end printErrorMsg + // The Lexer // ========== static bool skippedWhiteSpace( ) { // return true if not at EOF, i.e. if skipped @@ -123,7 +134,81 @@ static Token gettok( ) { // Note that the recursive descent function for (e.g.) E´ // is nameded "E2ndHalf"- +// Forward Declarations +static numberType E(); +static numberType E2ndHalf(); +static numberType T(); +static numberType T2ndHalf(); +static numberType F(); + +// E → T E´ +numberType E() { return T() + E2ndHalf(); } + +// T → F T´ +numberType T() { return F() * T2ndHalf(); } + +// E´ → + T E´ | - T E´ | ε +numberType E2ndHalf() { + switch ( next_token ) { + case tok_plus : + next_token = gettok(); // eat + + return T() + E2ndHalf(); + + case tok_minus : + next_token = gettok(); // eat - + return (-1.0 * T()) + E2ndHalf(); + default : + return 0.0; + }; +} // end E2ndHalf + +// T´ → * F T´ | / F T´ | ε +numberType T2ndHalf() { + numberType tmp, rhs, acc; + switch ( next_token ) { + case tok_times : + next_token = gettok(); // eat * + return F() * T2ndHalf(); + case tok_div : + next_token = gettok(); // eat / + tmp = F(); + if ( 0.0 != tmp ) + return (1.0/tmp) * T2ndHalf(); + // else if T() returned zero + printErrorMsg( "Division by zero!" ); + // fall through to default return one + + default : + return 1.0; + }; +} // end T2ndHalf + +// F → ( E ) | num +numberType F() { + numberType result = 0; + switch ( next_token ) { + case tok_lparen : + next_token = gettok(); // eat lparen + result = E(); + if ( tok_rparen == next_token ) { + next_token = gettok(); // eat rparen + return result; + }; + // else if rparen not found + printErrorMsg( "Expected Right Parenthesis" ); + return 0.0; + + case tok_number : + result = currentNumber; // side-effect of last gettok() + next_token = gettok(); // eat id + return result; + + default : + printErrorMsg( "Expected Left Parenthesis or number" ); + return 0.0; + }; +} // main (!) @@ -148,12 +233,12 @@ int main( int argc, char **argv ) { // get tokens and dump them... while ( tok_eof != next_token ) { - std::cout << "TOKEN = " << (char)next_token - << " current num = " << currentNumber - << std::endl; - next_token = gettok(); + std::cout << currentLineNumber << ":" + << currentLine << std::endl; + numberType value = E( ); + std::cout << "INTERPRETER: " << value << std::endl; }; - std::cout << "EOF" << std::endl; + std::cout << "End Of File!" << std::endl; return 0; // Alles klar!!! } diff --git a/recursiveDescentParsers/cplusplus/interpreter/testInput.txt b/recursiveDescentParsers/cplusplus/interpreter/testInput.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c49594be4b299e555ffbe7865109c33dcbf9497 --- /dev/null +++ b/recursiveDescentParsers/cplusplus/interpreter/testInput.txt @@ -0,0 +1,11 @@ +42 +40 + 2 +(44.44 - 2.44) +(21 * 2.0) +(84.0 / (3-1)) +88 / 2 - 2 +88 / (8 / 4) - 2 +44.0 - 2 +(4 * 11.0) - 2 +(8 * 11.0) / 2 - 2 +(8 * 11.0) / (8 / 4) - 2 diff --git a/recursiveDescentParsers/cplusplus/interpreter/testOutput.txt b/recursiveDescentParsers/cplusplus/interpreter/testOutput.txt new file mode 100644 index 0000000000000000000000000000000000000000..91ba1de4c0c4203951ea6357145c1320be54bad6 --- /dev/null +++ b/recursiveDescentParsers/cplusplus/interpreter/testOutput.txt @@ -0,0 +1,23 @@ +0:42 +INTERPRETER: 42 +1:40 + 2 +INTERPRETER: 42 +2:(44.44 - 2.44) +INTERPRETER: 42 +3:(21 * 2.0) +INTERPRETER: 42 +4:(84.0 / (3-1)) +INTERPRETER: 42 +5:88 / 2 - 2 +INTERPRETER: 42 +6:88 / (8 / 4) - 2 +INTERPRETER: 42 +7:44.0 - 2 +INTERPRETER: 42 +8:(4 * 11.0) - 2 +INTERPRETER: 42 +9:(8 * 11.0) / 2 - 2 +INTERPRETER: 42 +10:(8 * 11.0) / (8 / 4) - 2 +INTERPRETER: 42 +End Of File!