Skip to content

Commit 1d7583d

Browse files
committed
version with interpreter, but interpreter still bugged. for iinterpreter we use a function array instead of case statement
1 parent f5c2345 commit 1d7583d

File tree

7 files changed

+249
-163
lines changed

7 files changed

+249
-163
lines changed

defs.h

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,40 @@
11
#ifndef DEFS_H
22
#define DEFS_H
33
#include <string>
4+
#include <stdio.h>
45

56
using namespace std;
67
// PASS 1 will scan the input test and generate a list of symbols (see PASS1)
78
// we will assign a type to each allowed character .
89
// e.g. character 'h' (ascii 104) is a LETT, character '0' (ascii 48 )is a DIGIT. character (40) is PAR_L (left parenthesis)
910
// the following are the possible character types:
10-
enum KarType {ETX,
11-
LF,
12-
TAB,
13-
BLANK,
14-
HASHT,
15-
PAR_L,
16-
PAR_R,
17-
DOT,
18-
TIMES,
19-
DIV,
20-
PLUS,
21-
MINUS,
22-
EQ,
23-
GT,
24-
LT,
25-
COLON,
26-
QUEST, // we ignore this operator, becase ':' takes care of ternary, else QUESTION("[?]"),
27-
LETT,
28-
DIGIT,
29-
CR,
30-
OTHER,
31-
EXCLA,
32-
TEST};
33-
34-
//PASS 2 will scan the output of PASS1 and generate a list of symbols
35-
enum TokenType {
36-
// https://en.cppreference.com/w/cpp/language/operator_precedence#cite_note-2
37-
// of https://en.wikipedia.org/wiki/Order_of_operations
38-
COMMENT,
39-
VARI,
40-
LIT, //literal
41-
CHS, // CHS "change sign " was OP_3
42-
TimesDiv, // * or /, according to precedence order - was OP5
43-
PlusMin, // + or - - was OP6
44-
OP_16, // like elvis
45-
ELV_Q,
46-
ELV_C,
47-
BEXPS,
48-
BEXPE,
49-
EOT,
50-
NONE} ;
11+
enum KarType
12+
{ETX, LF, TAB, BLANK, HASHT, PAR_L, PAR_R, DOT, TIMES, DIV, PLUS, MINUS, LT, EQ, GT, QUEST, COLON, LETT, DIGIT, CR, OTHER, EXCLA, TEST};
13+
14+
15+
//PASS 2 will scan the output of PASS1 and generate a list of tokens
16+
// precedence is according to https://en.cppreference.com/w/cpp/language/operator_precedence#cite_note-2
17+
// or https://en.wikipedia.org/wiki/Order_of_operations
18+
enum TokenType
19+
{COMMENT, VARI, LIT, NUM, CHS, TimesDiv, PlusMin, COMPARE, ELV_Q, ELV_C, BEXPS, BEXPE, EOT, NONE};
20+
21+
// to go from KarType to TokenType we use an array:
22+
TokenType tokenType[32] =
23+
{NONE, NONE, NONE, NONE, NONE, BEXPS, BEXPE, NONE, TimesDiv, TimesDiv, NONE, NONE, COMPARE,COMPARE,COMPARE, ELV_C, ELV_Q, LIT, NUM, NONE, NONE, EOT, NONE};
24+
// {ETX, LF, TAB, BLANK, HASHT, PAR_L, PAR_R, DOT, TIMES, DIV, PLUS, MINUS, LT, EQ, GT, QUEST, COLON, LETT, DIGIT, CR, OTHER, EXCLA, TEST};
25+
// prettyPrint of TokenType:
26+
string ppTokenType[32] = {"com", "VAR", "LIT", "NUM", "CHS", "*/", "+-" , "CMPR", "?", ":", "(", ")", "EOT", "NON"};
27+
28+
enum Opcode {oCHS, oMUL, oDIV, oSUM, oMIN, oLT, oEQ, oGT, oQUE, oCOL, oNONE};
29+
30+
//codes 0 0 1 2 3 4 5 6 0 -1 -1
31+
//arity 1 2 2 2 2 2 2 2 3 -1 -1
5132

5233
typedef struct {
5334
TokenType type;
54-
int arity;
5535
string content;
36+
int opcode;
37+
int arity;
5638
int cursor;
5739
} Token;
5840

@@ -91,7 +73,7 @@ void initDinges(){
9173
kartyp[63] = QUEST; KarPP[63] = "?";
9274
}
9375

94-
// finally our maain data structures:
76+
// finally our main data structures:
9577
// 1. the input expression as a text string:
9678
string textIn= "";
9779
// 2. the output of PASS1 as a vector of symbols. it is also the input for PASS2.

expressionparser.pro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
QT += core
22
QT -= gui
33

4-
CONFIG += c++11
4+
CONFIG += c++17
55

66
TARGET = expressionparser
77
CONFIG += console
@@ -13,6 +13,7 @@ SOURCES += main.cpp
1313

1414
HEADERS += \
1515
defs.h \
16+
interpreter.h \
1617
pass1.h \
1718
pass2.h \
1819
utils.h

interpreter.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#ifndef INTERPRETER_H
2+
#define INTERPRETER_H
3+
4+
5+
float calc1(vector<Token>& s){
6+
int opsign;
7+
Token last;
8+
last = s.back(); s.pop_back();
9+
if (last.type == NUM) return stof(last.content); // todo also LIT VARI?
10+
else
11+
opsign = last.opcode;
12+
float v1 = calc1(s);
13+
float v2 = calc1(s);
14+
switch(opsign) {
15+
case oMUL: return v2 * v1;
16+
case oDIV: return v2 / v1;
17+
case oSUM: return v2 + v1;
18+
case oMIN: return v2 - v1;
19+
case oLT: if (v2 < v1) return 1; else return 0;
20+
case oEQ: if (v2 == v1) return 1; else return 0;
21+
case oGT: if (v2 > v1) return 1; else return 0;
22+
// "?" -> return v1
23+
case oCOL: {
24+
float v3 = calc1(s);
25+
if (v3 > 0) return v2; else return v1;
26+
}
27+
}
28+
}
29+
30+
float calc(vector<Token>& s){
31+
int opcode;
32+
float v1;
33+
float v2;
34+
float v3;
35+
Token last = s.back(); s.pop_back();
36+
if (last.content == "?") {last = s.back(); s.pop_back();};
37+
if (last.type == NUM) return stof(last.content); // todo also LIT VARI?
38+
switch (last.arity){
39+
case 1: v1 =calc(s); return -v1;
40+
case 2: v1 =calc(s); v2 =calc(s); return op2[last.opcode](v1,v2);
41+
case 3:
42+
v1 =calc(s); v2 =calc(s); v3 =calc(s);
43+
// op3[last.opcode](v1,v2,v3);
44+
if (v1 > 0.5) return v2; else return v3;
45+
}
46+
}
47+
48+
49+
void calcandprint(vector<Token> s) {
50+
cout << "RESULT ==> " << float(calc(s)) << endl;
51+
}
52+
53+
54+
55+
56+
#endif // INTERPRETER_H

main.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,34 @@ void reportElapsedTime(string msg){
2727
}
2828

2929
#include <pass1.h>
30-
3130
#include <pass2.h>
31+
#include <interpreter.h>
3232

33-
34-
35-
Token tt = {VARI, 0, "haha", 0}; //test
3633
int main(int argc, char *argv[])
3734
{
3835
(void)(argc);(void)(argv);
3936
initDinges();
37+
initOperators();
4038

4139
//tests
4240
cout << "testing ... \n" << int(c) << endl;
4341

42+
// cout << "invoke: " << invoke(2,3, op_add) << endl;
43+
44+
cout << "invoke: " << op2[1](2,3) << endl;
4445

45-
textIn = "2+(12*(3<4 ?(4/2)*5:(17-5)*3))!";
46+
47+
textIn = "-2+(-a3<4 ?4*5:(17-5)*3)!";
48+
// textIn = "(2+3)*((1<2) + (6-2)/2)!";
49+
// textIn = "2*5!";
4650
cout << "textIn is: " << textIn << endl;
47-
cout << "\nPASS 1 gives : "; parse1();
48-
printVector(symList);
51+
cout << "\nPASS 1 gives :\n"; parse1();
52+
printPass2(symList, 4);
4953
cout << "\nPASS 2 says : "; parse2();
50-
printVector(symListOut);
54+
printPass2(symListOut, 5);
55+
56+
calcandprint(symListOut);
57+
5158
cout << "\n\nthe end"<< endl;
5259

5360
return 0;

pass1.h

Lines changed: 79 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -16,104 +16,99 @@ Token makeSymbol(vector<TokenType> expected){
1616
return makeSymbol({}); //makesymbol advances the cursor
1717
}
1818
int intc = int(c);
19-
int tup = kartyp[int(c)];
20-
symIn.content = KarPP[int(c)]; // pretty print
21-
switch (tup) {
22-
case LETT: case DIGIT: case DOT: //c is a KAR, so we're building a string
23-
s = "";
24-
while (isaC(c, {LETT, DIGIT, DOT})) {
25-
s += c;
26-
cursor++;
27-
c = textIn[cursor];
28-
};
29-
symIn.type = VARI;
30-
symIn.content = s;
31-
cursor--;
32-
break;
33-
case EXCLA: case ETX: case LF: case CR: case OTHER:
34-
symIn.type = EOT;
35-
return symIn;
36-
break;
37-
case PAR_L:
38-
symIn.type = BEXPS; //the special character becomes the typ
39-
break;
40-
case PAR_R:
41-
symIn.type = BEXPE; //the special character becomes the typ
42-
break;
43-
case TIMES: case DIV: case GT: case LT: case EQ:
44-
if (! (isFirstSymbol)) { //we have a separator
45-
symIn.type = TimesDiv; //the special character becomes the typ
46-
}
47-
break;
48-
case QUEST:
49-
symIn.type = ELV_Q; //the special character becomes the typ
50-
break;
51-
case COLON:
52-
symIn.type = ELV_C; //the special character becomes the typ
53-
break;
54-
case PLUS: case MINUS:
55-
if (isFirstSymbol) {
56-
symIn.type = CHS;
57-
} else if (isaC(textIn[cursor - 1], {TIMES, DIV, PLUS, MINUS, PAR_L, QUEST})) {
58-
// we are not adding to the previous, this is a unary operator
59-
symIn.type = CHS;
60-
} else symIn.type = PlusMin;
61-
break;
62-
case TEST: //c is a KAR, so we're building a string
63-
// var s = "";
64-
// s += c;
65-
// cursor++
66-
// c = textIn[cursor]
67-
// while (isaC(c, LETT, DIGIT)) {
68-
// s += c;
69-
// cursor++
70-
// c = textIn[cursor]
71-
// }
72-
// symIn.typ = VARI;
73-
// symIn.content = s
74-
break;
75-
default:
76-
symIn.type = NONE; //the special character becomes the typ
77-
break;
78-
}
19+
20+
symIn.content = KarPP[int(c)]; // pretty print
21+
symIn.opcode = -1;
22+
KarType karTypeIn = kartyp[int(c)];
23+
switch (karTypeIn) {
24+
case LETT: case DIGIT: case DOT: //c is a KAR, so we're building a string
25+
s = "";
26+
while (isaC(c, {LETT, DIGIT, DOT})) {
27+
s += c;
28+
cursor++;
29+
c = textIn[cursor];
30+
};
31+
if (karTypeIn == DIGIT ) symIn.type = NUM; else symIn.type = LIT;
32+
symIn.content = s;
33+
cursor--;
34+
break;
35+
case TIMES:
36+
symIn.type = TimesDiv; symIn.opcode = 0; symIn.arity = 2; //oMUL; //we have a separator
37+
break;
38+
case DIV:
39+
symIn.type = TimesDiv; symIn.opcode = 1; symIn.arity = 2; //oDIV; //we have a separator
40+
break;
41+
case PLUS:
42+
if (isFirstSymbol) {symIn.type = CHS; symIn.opcode = 0;} //oCHS;}
43+
else if (isaC(textIn[cursor - 1], {TIMES, DIV, PLUS, MINUS, PAR_L, QUEST})) {
44+
// we are not adding to the previous, this is a unary operator
45+
symIn.type = CHS; symIn.opcode = 0; //oCHS;
46+
} else {symIn.type = PlusMin; symIn.opcode = 2;} //oSUM;}
47+
break;
48+
case MINUS:
49+
if (isFirstSymbol) {symIn.type = CHS; symIn.opcode = 0; symIn.arity = 1; } //oCHS;}
50+
else if (isaC(textIn[cursor - 1], {TIMES, DIV, PLUS, MINUS, PAR_L, QUEST})) {
51+
// we are not adding to the previous, this is a unary operator
52+
symIn.type = CHS; symIn.opcode = 0; symIn.arity = 1; //oCHS;
53+
} else {symIn.type = PlusMin; symIn.opcode = 3;} //oMIN;}
54+
break;
55+
case LT:
56+
symIn.type = COMPARE; symIn.opcode = 4; symIn.arity = 2; //oLT;
57+
break;
58+
case EQ:
59+
symIn.type = COMPARE; symIn.opcode = 5; symIn.arity = 2; //oEQ;
60+
break;
61+
case GT:
62+
symIn.type = COMPARE; symIn.opcode = 6; symIn.arity = 2; //oGT;
63+
break;
64+
case QUEST:
65+
symIn.type = ELV_Q; symIn.opcode = 0; //oQUE;
66+
break;
67+
case COLON:
68+
symIn.type = ELV_C; symIn.opcode = -1; symIn.arity = 13;
69+
break;
70+
default:
71+
symIn.type = tokenType[kartyp[int(c)]];
72+
symIn.opcode = -1;
73+
break;
74+
}
7975
isFirstSymbol = false;
8076
cursor++;
81-
if (expected.empty()) return symIn; //default, we do not complain
82-
if (count(expected.begin(), expected.end(), symIn.type) > 0) return symIn; //check on expected char is ok, no complaints
83-
errorsPresent = true;
77+
if (expected.empty()) return symIn; //default, we do not complain
78+
if (count(expected.begin(), expected.end(), symIn.type) > 0) return symIn; //check on expected char is ok, no complaints
79+
errorsPresent = true;
8480
// throw IllegalArgumentException(
8581
// "SEPARATOR in line at cursor " +
8682
// "$cursor < ${textIn.substring(0, cursor)} > \n" +
8783
// " char=$c, symbol=${symIn.content} ==> < ${expected.contentToString()} >\n"
8884
// );
89-
return symIn;
85+
return symIn;
9086
}
9187

9288
void clear1() {
93-
cursor = 0;
94-
errorsPresent = false;
95-
symList.clear();
89+
cursor = 0;
90+
errorsPresent = false;
91+
symList.clear();
9692
}
9793

9894
vector<Token> parse1(){
99-
clear1();
100-
cursor = 0;
101-
errorsPresent = false;
102-
reportln("textIn = $textIn", 0);
103-
do {
104-
symIn = makeSymbol({});
105-
if (isa(symIn, {ELV_C})) { // substitute '?(' for '?'
106-
symList.push_back({BEXPE, 17, ")", cursor}); //todo pretty print
107-
};
108-
symList.push_back({symIn.type, 17, symIn.content, cursor});
109-
if (isa(symIn, {ELV_Q})) { // substitute '?(' for '?'
110-
symList.push_back({BEXPS, 17, "(", cursor}); //todo
111-
};
112-
} while (symIn.type != EOT);
95+
clear1();
96+
cursor = 0;
97+
errorsPresent = false;
98+
do {
99+
symIn = makeSymbol({});
113100

114-
reportln(symList, 1, 7);
115-
cout << "\n";
116-
return symList;
101+
// in case of a "? XXX : YYY" construct we insert parentheses around the XXX part. this isolates the expression XXX
102+
if (isa(symIn, {ELV_C})) { // substitute '?(' for '?'
103+
symList.push_back({BEXPE, ")", oCOL, -1, cursor});
104+
};
105+
symList.push_back(symIn);
106+
// symList.push_back({symIn.type, symIn.content, oNONE, -1, cursor});
107+
if (isa(symIn, {ELV_Q})) { // substitute '?(' for '?'
108+
symList.push_back({BEXPS, "(", oQUE, -1, cursor}); //
109+
};
110+
} while (symIn.type != EOT);
111+
return symList;
117112
}
118113

119114

0 commit comments

Comments
 (0)