Download code
From LiteratePrograms
Back to Shunting_yard_algorithm_(C)
Download for Windows: single file, zip
Download for UNIX: single file, zip, tar.gz, tar.bz2
shunt.c
1 /* Copyright (c) 2010 the authors listed at the following URL, and/or 2 the authors of referenced articles or incorporated external code: 3 http://en.literateprograms.org/Shunting_yard_algorithm_(C)?action=history&offset=20080201043325 4 5 Permission is hereby granted, free of charge, to any person obtaining 6 a copy of this software and associated documentation files (the 7 "Software"), to deal in the Software without restriction, including 8 without limitation the rights to use, copy, modify, merge, publish, 9 distribute, sublicense, and/or sell copies of the Software, and to 10 permit persons to whom the Software is furnished to do so, subject to 11 the following conditions: 12 13 The above copyright notice and this permission notice shall be 14 included in all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 Retrieved from: http://en.literateprograms.org/Shunting_yard_algorithm_(C)?oldid=12454 25 */ 26 27 28 #include<stdlib.h> 29 #include<stdio.h> 30 #include<ctype.h> 31 32 #define MAXOPSTACK 64 33 #define MAXNUMSTACK 64 34 35 int eval_uminus(int a1, int a2) 36 { 37 return -a1; 38 } 39 int eval_exp(int a1, int a2) 40 { 41 return a2<0 ? 0 : (a2==0?1:a1*eval_exp(a1, a2-1)); 42 } 43 int eval_mul(int a1, int a2) 44 { 45 return a1*a2; 46 } 47 int eval_div(int a1, int a2) 48 { 49 if(!a2) { 50 fprintf(stderr, "ERROR: Division by zero\n"); 51 exit(EXIT_FAILURE); 52 } 53 return a1/a2; 54 } 55 int eval_mod(int a1, int a2) 56 { 57 if(!a2) { 58 fprintf(stderr, "ERROR: Division by zero\n"); 59 exit(EXIT_FAILURE); 60 } 61 return a1%a2; 62 } 63 int eval_add(int a1, int a2) 64 { 65 return a1+a2; 66 } 67 int eval_sub(int a1, int a2) 68 { 69 return a1-a2; 70 } 71 72 73 74 enum {ASSOC_NONE=0, ASSOC_LEFT, ASSOC_RIGHT}; 75 76 struct op_s { 77 char op; 78 int prec; 79 int assoc; 80 int unary; 81 int (*eval)(int a1, int a2); 82 } ops[]={ 83 {'_', 10, ASSOC_RIGHT, 1, eval_uminus}, 84 {'^', 9, ASSOC_RIGHT, 0, eval_exp}, 85 {'*', 8, ASSOC_LEFT, 0, eval_mul}, 86 {'/', 8, ASSOC_LEFT, 0, eval_div}, 87 {'%', 8, ASSOC_LEFT, 0, eval_mod}, 88 {'+', 5, ASSOC_LEFT, 0, eval_add}, 89 {'-', 5, ASSOC_LEFT, 0, eval_sub}, 90 {'(', 0, ASSOC_NONE, 0, NULL}, 91 {')', 0, ASSOC_NONE, 0, NULL} 92 }; 93 94 struct op_s *getop(char ch) 95 { 96 int i; 97 for(i=0; i<sizeof ops/sizeof ops[0]; ++i) { 98 if(ops[i].op==ch) return ops+i; 99 } 100 return NULL; 101 } 102 103 104 struct op_s *opstack[MAXOPSTACK]; 105 int nopstack=0; 106 107 int numstack[MAXNUMSTACK]; 108 int nnumstack=0; 109 110 void push_opstack(struct op_s *op) 111 { 112 if(nopstack>MAXOPSTACK-1) { 113 fprintf(stderr, "ERROR: Operator stack overflow\n"); 114 exit(EXIT_FAILURE); 115 } 116 opstack[nopstack++]=op; 117 } 118 119 struct op_s *pop_opstack() 120 { 121 if(!nopstack) { 122 fprintf(stderr, "ERROR: Operator stack empty\n"); 123 exit(EXIT_FAILURE); 124 } 125 return opstack[--nopstack]; 126 } 127 128 void push_numstack(int num) 129 { 130 if(nnumstack>MAXNUMSTACK-1) { 131 fprintf(stderr, "ERROR: Number stack overflow\n"); 132 exit(EXIT_FAILURE); 133 } 134 numstack[nnumstack++]=num; 135 } 136 137 int pop_numstack() 138 { 139 if(!nnumstack) { 140 fprintf(stderr, "ERROR: Number stack empty\n"); 141 exit(EXIT_FAILURE); 142 } 143 return numstack[--nnumstack]; 144 } 145 146 147 148 void shunt_op(struct op_s *op) 149 { 150 struct op_s *pop; 151 int n1, n2; 152 153 if(op->op=='(') { 154 push_opstack(op); 155 return; 156 157 } else if(op->op==')') { 158 while(nopstack>0 && opstack[nopstack-1]->op!='(') { 159 pop=pop_opstack(); 160 n1=pop_numstack(); 161 162 if(pop->unary) push_numstack(pop->eval(n1, 0)); 163 else { 164 n2=pop_numstack(); 165 push_numstack(pop->eval(n2, n1)); 166 } 167 } 168 169 if(!(pop=pop_opstack()) || pop->op!='(') { 170 fprintf(stderr, "ERROR: Stack error. No matching \'(\'\n"); 171 exit(EXIT_FAILURE); 172 } 173 return; 174 } 175 176 if(op->assoc==ASSOC_RIGHT) { 177 while(nopstack && op->prec<opstack[nopstack-1]->prec) { 178 pop=pop_opstack(); 179 n1=pop_numstack(); 180 if(pop->unary) push_numstack(pop->eval(n1, 0)); 181 else { 182 n2=pop_numstack(); 183 push_numstack(pop->eval(n2, n1)); 184 } 185 } 186 } else { 187 while(nopstack && op->prec<=opstack[nopstack-1]->prec) { 188 pop=pop_opstack(); 189 n1=pop_numstack(); 190 if(pop->unary) push_numstack(pop->eval(n1, 0)); 191 else { 192 n2=pop_numstack(); 193 push_numstack(pop->eval(n2, n1)); 194 } 195 } 196 } 197 push_opstack(op); 198 } 199 200 201 202 int main(int argc, char *argv[]) 203 { 204 char *expr; 205 char *tstart=NULL; 206 struct op_s startop={'X', 0, ASSOC_NONE, 0, NULL}; /* Dummy operator to mark start */ 207 struct op_s *op=NULL; 208 int n1, n2; 209 struct op_s *lastop=&startop; 210 211 if(argc<2) { 212 fprintf(stderr, "Usage: %s <expression>\n", argv[0]); 213 return EXIT_FAILURE; 214 } 215 216 for(expr=argv[1]; *expr; ++expr) { 217 if(!tstart) { 218 219 if((op=getop(*expr))) { 220 221 if(lastop && (lastop==&startop || lastop->op!=')')) { 222 if(op->op=='-') op=getop('_'); 223 else if(op->op!='(') { 224 fprintf(stderr, "ERROR: Illegal use of binary operator (%c)\n", op->op); 225 exit(EXIT_FAILURE); 226 } 227 } 228 shunt_op(op); 229 lastop=op; 230 } else if(isdigit(*expr)) tstart=expr; 231 else if(!isspace(*expr)) { 232 fprintf(stderr, "ERROR: Syntax error\n"); 233 return EXIT_FAILURE; 234 } 235 } else { 236 if(isspace(*expr)) { 237 push_numstack(atoi(tstart)); 238 tstart=NULL; 239 lastop=NULL; 240 } else if((op=getop(*expr))) { 241 push_numstack(atoi(tstart)); 242 tstart=NULL; 243 shunt_op(op); 244 lastop=op; 245 } else if(!isdigit(*expr)) { 246 fprintf(stderr, "ERROR: Syntax error\n"); 247 return EXIT_FAILURE; 248 } 249 } 250 } 251 if(tstart) push_numstack(atoi(tstart)); 252 253 254 while(nopstack) { 255 op=pop_opstack(); 256 n1=pop_numstack(); 257 if(op->unary) push_numstack(op->eval(n1, 0)); 258 else { 259 n2=pop_numstack(); 260 push_numstack(op->eval(n2, n1)); 261 } 262 } 263 264 if(nnumstack!=1) { 265 fprintf(stderr, "ERROR: Number stack has %d elements after evaluation. Should be 1.\n", nnumstack); 266 return EXIT_FAILURE; 267 } 268 printf("%d\n", numstack[0]); 269 270 return EXIT_SUCCESS; 271 } 272 273 274 275
