Ik zou het nou juist weer niet eerst naar postfix omzetten. Dat is verspilde moeite, want terwijl je dat aan het doen bent ben je toch alle regels voor volgorde aan het parsen, als je dat dan toch doet, dan kan je ook gelijk de getallen wel meenemen.
Ik zou dus even een simpel context vrij grammatica'tje in elkaar zetten.
Code lijkt veel, maar het is veel knip en plak werk
Als je dan ook met constantes wilt rekenen, moet je die voodat je hieraan begint even een string search op de namen van je constantes zoeken en dan die vervangen door je waardes. Of als je het echt volgens het boekje wilt doen haal je die op in N (RuleN).
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
| #include <iostream>
#include <string>
using namespace std;
/* This simple grammar without left recursion gives us our rules:
S -> A-S | A A=Add
A -> D+A | D D=Divide
D -> M/D | M M=Multiply
M -> P*M | P P=Power
P -> N^P | N N=Number
N -> (S) | float */
int RuleS(char *ParseString,float *result);
int RuleA(char *ParseString,float *result);
int RuleD(char *ParseString,float *result);
int RuleM(char *ParseString,float *result);
int RuleP(char *ParseString,float *result);
int RuleN(char *ParseString,float *result);
/* All rule function have as in what is left to parse
in result the inmediate result is stored
return is how many characters are read or -1 on syntax error
*/
int main(void)
{
char *expression=(char *)malloc(1024);
cin >> expression;
float answer;
if ((charcount > 0) && (*(expression+charcount)=='\0')) {
cout << answer << "\n";
} else {
cout << "Syntax error\n";
}
return 0;
}
// Subtract Rule
int RuleS(char *ParseString,float *result)
{
float operant1;
float operant2;
int totalcharcount=0;
int charcount=RuleA(ParseString,&operant1);
totalcharcount+=charcount;
if (charcount < 0) return -1; // pass up error
if (*(ParseString+charcount)=='-') {
charcount=RuleS(ParseString+totalcharcount+1,&operant2);
if (charcount < 0) return -1; // pass up error
totalcharcount+=charcount+1;
*result=operant1-operant2;
} else {
*result=operant1;
}
return totalcharcount;
}
// Add Rule
int RuleA(char *ParseString,float *result)
{
float operant1;
float operant2;
int totalcharcount=0;
int charcount=RuleD(ParseString,&operant1);
totalcharcount+=charcount;
if (charcount < 0) return -1; // pass up error
if (*(ParseString+charcount)=='+') {
charcount=RuleA(ParseString+totalcharcount+1,&operant2);
if (charcount < 0) return -1; // pass up error
totalcharcount+=charcount+1;
*result=operant1+operant2;
} else {
*result=operant1;
}
return totalcharcount;
}
// Divide Rule
int RuleD(char *ParseString,float *result)
{
float operant1;
float operant2;
int totalcharcount=0;
int charcount=RuleM(ParseString,&operant1);
totalcharcount+=charcount;
if (charcount < 0) return -1; // pass up error
if (*(ParseString+charcount)=='/') {
charcount=RuleD(ParseString+totalcharcount+1,&operant2);
if (charcount < 0) return -1; // pass up error
totalcharcount+=charcount+1;
*result=operant1+operant2;
} else {
*result=operant1;
}
return totalcharcount;
}
// Multiply Rule
int RuleM(char *ParseString,float *result)
{
float operant1;
float operant2;
int totalcharcount=0;
int charcount=RuleP(ParseString,&operant1);
totalcharcount+=charcount;
if (charcount < 0) return -1; // pass up error
if (*(ParseString+charcount)=='*') {
charcount=RuleM(ParseString+totalcharcount+1,&operant2);
if (charcount < 0) return -1; // pass up error
totalcharcount+=charcount+1;
*result=operant1*operant2;
} else {
*result=operant1;
}
return totalcharcount;
}
// Power Rule
int RuleP(char *ParseString,float *result)
{
float operant1;
float operant2;
int totalcharcount=0;
int charcount=RuleN(ParseString,&operant1);
totalcharcount+=charcount;
if (charcount < 0) return -1; // pass up error
if (*(ParseString+charcount)=='^') {
charcount=RuleP(ParseString+totalcharcount+1,&operant2);
if (charcount < 0) return -1; // pass up error
totalcharcount+=charcount+1;
*result=pow(operant1,operant2);
} else {
*result=operant1;
}
return totalcharcount;
}
// Parse Numerical or brackets
int RuleN(char *ParseString,float *result)
{
*result=0;
int charcount=0;
if (*ParseString=='('){
charcount=RuleS(ParseString+1,result);
if (charcount < 0) return -1;
if (*(ParseString+1+charcount)!=')') {
cout << "Mising closing bracket\n";
return -1;
}
return charcount+2;
}
while ((*(ParseString+charcount)>='0') && (*(ParseString+charcount)<='9')) {
*result*=10;
*result+=*(ParseString+charcount)-'0';
charcount++;
}
if (*(ParseString+charcount)=='.') {
charcount++;
int Base=1;
while ((*(ParseString+charcount)>='0') && (*(ParseString+charcount)<='9')) {
Base*=10;
*result+=((float)(*(ParseString+charcount)-'0'))/(float)Base;
charcount++;
}
}
if (charcount==0) {
cout << "Syntax error\n";
return -1;
}
return charcount;
} |
code:
1
2
3
4
5
6
7
8
9
10
| $ g++ SimpleGrammar.cpp -o SimpleGrammar
$ ./SimpleGrammar
2*3+3*2
12
$ ./SimpleGrammar
2^8-1
255
$ ./SimpleGrammar
2^0.5*(3-1)^0.5
2 |
zoals je ziet netje Meneer van Dale wacht de volgordes in je grammatica bepalen wat eerst bindt.
[
Voor 5% gewijzigd door
Semyon op 03-03-2005 06:55
]