| 1 | // This file is part of SmallBASIC | 
|---|
| 2 | // | 
|---|
| 3 | // pseudo-compiler: expressions (warning: the input is byte-code segment) | 
|---|
| 4 | // | 
|---|
| 5 | // This program is distributed under the terms of the GPL v2.0 or later | 
|---|
| 6 | // Download the GNU Public License (GPL) from www.gnu.org | 
|---|
| 7 | // | 
|---|
| 8 | // Copyright(C) 2000 Nicholas Christopoulos | 
|---|
| 9 |  | 
|---|
| 10 | #include "common/smbas.h" | 
|---|
| 11 | #include "common/bc.h" | 
|---|
| 12 |  | 
|---|
| 13 | static bc_t *bc_in; | 
|---|
| 14 | static bc_t *bc_out; | 
|---|
| 15 |  | 
|---|
| 16 | #define cev_add1(x)     bc_add_code(bc_out, (x)) | 
|---|
| 17 | #define cev_add2(x, y)  { bc_add1(bc_out, (x)); bc_add1(bc_out, (y)); } | 
|---|
| 18 | #define cev_add_addr(x) bc_add_addr(bc_out, (x)) | 
|---|
| 19 | #define IP              bc_in->cp | 
|---|
| 20 | #define CODE(x)         bc_in->ptr[(x)] | 
|---|
| 21 | #define CODE_PEEK()     CODE(IP) | 
|---|
| 22 | #define IF_ERR_RTN      if (comp_error) return | 
|---|
| 23 |  | 
|---|
| 24 | void cev_log(void); | 
|---|
| 25 |  | 
|---|
| 26 | void cev_udp(void) { | 
|---|
| 27 | sc_raise( "(EXPR): UDP INSIDE EXPR"); | 
|---|
| 28 | } | 
|---|
| 29 |  | 
|---|
| 30 | void cev_missing_rp(void) { | 
|---|
| 31 | sc_raise( "(EXPR): MISSING ')'"); | 
|---|
| 32 | } | 
|---|
| 33 |  | 
|---|
| 34 | void cev_opr_err(void) { | 
|---|
| 35 | sc_raise( "(EXPR): SYNTAX ERROR (%d)", CODE(IP)); | 
|---|
| 36 | } | 
|---|
| 37 |  | 
|---|
| 38 | void cev_prim_str() { | 
|---|
| 39 | uint32_t len; | 
|---|
| 40 | memcpy(&len, bc_in->ptr + bc_in->cp, OS_STRLEN); | 
|---|
| 41 | IP += OS_STRLEN; | 
|---|
| 42 | bc_add_dword(bc_out, len); | 
|---|
| 43 | bc_add_n(bc_out, bc_in->ptr + bc_in->cp, len); | 
|---|
| 44 | IP += len; | 
|---|
| 45 | } | 
|---|
| 46 |  | 
|---|
| 47 | void cev_prim_uds() { | 
|---|
| 48 | while (CODE_PEEK() == kwTYPE_UDS_EL) { | 
|---|
| 49 | cev_add1(kwTYPE_UDS_EL); | 
|---|
| 50 | cev_add1(kwTYPE_STR); | 
|---|
| 51 | IP += 2; | 
|---|
| 52 | cev_prim_str(); | 
|---|
| 53 | } | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | void cev_prim_var() { | 
|---|
| 57 | bc_add_n(bc_out, bc_in->ptr + bc_in->cp, ADDRSZ); | 
|---|
| 58 | IP += ADDRSZ; | 
|---|
| 59 |  | 
|---|
| 60 | cev_prim_uds(); | 
|---|
| 61 |  | 
|---|
| 62 | // support multiple () | 
|---|
| 63 | while (CODE_PEEK() == kwTYPE_LEVEL_BEGIN) { | 
|---|
| 64 | cev_add1(kwTYPE_LEVEL_BEGIN); | 
|---|
| 65 | IP++; | 
|---|
| 66 | if (CODE_PEEK() == kwTYPE_LEVEL_END) { | 
|---|
| 67 | // NULL ARRAYS | 
|---|
| 68 | cev_add1(kwTYPE_LEVEL_END); | 
|---|
| 69 | IP++; | 
|---|
| 70 | } else { | 
|---|
| 71 | cev_log(); | 
|---|
| 72 |  | 
|---|
| 73 | while (CODE_PEEK() == kwTYPE_SEP || CODE_PEEK() == kwTO) { | 
|---|
| 74 | // DIM X(A TO B) | 
|---|
| 75 | if (CODE_PEEK() == kwTYPE_SEP) { | 
|---|
| 76 | cev_add1(CODE(IP)); | 
|---|
| 77 | IP++; | 
|---|
| 78 | } | 
|---|
| 79 | cev_add1(CODE(IP)); | 
|---|
| 80 | IP++; | 
|---|
| 81 |  | 
|---|
| 82 | cev_log(); | 
|---|
| 83 | } | 
|---|
| 84 |  | 
|---|
| 85 | if (CODE_PEEK() != kwTYPE_LEVEL_END) { | 
|---|
| 86 | cev_missing_rp(); | 
|---|
| 87 | } else { | 
|---|
| 88 | cev_add1(kwTYPE_LEVEL_END); | 
|---|
| 89 | IP++; | 
|---|
| 90 | cev_prim_uds(); | 
|---|
| 91 | } | 
|---|
| 92 | } | 
|---|
| 93 | } | 
|---|
| 94 | } | 
|---|
| 95 |  | 
|---|
| 96 | void cev_empty_args() { | 
|---|
| 97 | cev_add1(kwTYPE_LEVEL_BEGIN); | 
|---|
| 98 | cev_add1(kwTYPE_LEVEL_END); | 
|---|
| 99 | IP += 2; | 
|---|
| 100 | } | 
|---|
| 101 |  | 
|---|
| 102 | // function [(...)] | 
|---|
| 103 | void cev_prim_args() { | 
|---|
| 104 | cev_add1(kwTYPE_LEVEL_BEGIN); | 
|---|
| 105 | IP++; | 
|---|
| 106 |  | 
|---|
| 107 | if (CODE_PEEK() == kwTYPE_CALL_PTR) { | 
|---|
| 108 | cev_add1(CODE(IP)); | 
|---|
| 109 | IP++; | 
|---|
| 110 | } | 
|---|
| 111 |  | 
|---|
| 112 | if (CODE_PEEK() != kwTYPE_SEP) { | 
|---|
| 113 | // empty parameter | 
|---|
| 114 | cev_log(); | 
|---|
| 115 | } | 
|---|
| 116 | while (CODE_PEEK() == kwTYPE_SEP) { | 
|---|
| 117 | // while parameters | 
|---|
| 118 | cev_add1(CODE(IP)); | 
|---|
| 119 | IP++; | 
|---|
| 120 | cev_add1(CODE(IP)); | 
|---|
| 121 | IP++; | 
|---|
| 122 |  | 
|---|
| 123 | if (CODE_PEEK() != kwTYPE_LEVEL_END) { | 
|---|
| 124 | if (CODE_PEEK() != kwTYPE_SEP) { | 
|---|
| 125 | cev_log(); | 
|---|
| 126 | } | 
|---|
| 127 | } | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | // after (), check for UDS field, eg foo(10).x | 
|---|
| 131 | if (CODE_PEEK() == kwTYPE_UDS_EL) { | 
|---|
| 132 | cev_prim_uds(); | 
|---|
| 133 | cev_log(); | 
|---|
| 134 | } | 
|---|
| 135 |  | 
|---|
| 136 | if (CODE_PEEK() != kwTYPE_LEVEL_END) { | 
|---|
| 137 | cev_missing_rp(); | 
|---|
| 138 | } else { | 
|---|
| 139 | cev_add1(kwTYPE_LEVEL_END); | 
|---|
| 140 | IP++; | 
|---|
| 141 | } | 
|---|
| 142 | } | 
|---|
| 143 |  | 
|---|
| 144 | // test for repeated primatives | 
|---|
| 145 | void cev_check_dup_prim() { | 
|---|
| 146 | switch (CODE(IP)) { | 
|---|
| 147 | case kwTYPE_INT: | 
|---|
| 148 | case kwTYPE_NUM: | 
|---|
| 149 | case kwTYPE_STR: | 
|---|
| 150 | case kwTYPE_VAR: | 
|---|
| 151 | case kwTYPE_CALLF: | 
|---|
| 152 | cev_opr_err(); | 
|---|
| 153 | break; | 
|---|
| 154 | default: | 
|---|
| 155 | break; | 
|---|
| 156 | } | 
|---|
| 157 | } | 
|---|
| 158 |  | 
|---|
| 159 | /* | 
|---|
| 160 | * prim | 
|---|
| 161 | */ | 
|---|
| 162 | void cev_prim() { | 
|---|
| 163 | IF_ERR_RTN; | 
|---|
| 164 | byte code = CODE(IP); | 
|---|
| 165 | IP++; | 
|---|
| 166 | cev_add1(code); | 
|---|
| 167 | switch (code) { | 
|---|
| 168 | case kwTYPE_INT: | 
|---|
| 169 | bc_add_n(bc_out, bc_in->ptr + bc_in->cp, OS_INTSZ); | 
|---|
| 170 | IP += OS_INTSZ; | 
|---|
| 171 | cev_check_dup_prim(); | 
|---|
| 172 | break; | 
|---|
| 173 | case kwTYPE_NUM: | 
|---|
| 174 | bc_add_n(bc_out, bc_in->ptr + bc_in->cp, OS_REALSZ); | 
|---|
| 175 | IP += OS_REALSZ; | 
|---|
| 176 | cev_check_dup_prim(); | 
|---|
| 177 | break; | 
|---|
| 178 | case kwTYPE_STR: | 
|---|
| 179 | cev_prim_str(); | 
|---|
| 180 | cev_check_dup_prim(); | 
|---|
| 181 | break; | 
|---|
| 182 | case kwTYPE_CALL_UDP: | 
|---|
| 183 | cev_udp(); | 
|---|
| 184 | cev_check_dup_prim(); | 
|---|
| 185 | break; | 
|---|
| 186 | case kwTYPE_PTR: | 
|---|
| 187 | bc_add_n(bc_out, bc_in->ptr + bc_in->cp, ADDRSZ); // addr | 
|---|
| 188 | IP += ADDRSZ; | 
|---|
| 189 | bc_add_n(bc_out, bc_in->ptr + bc_in->cp, ADDRSZ); // return var | 
|---|
| 190 | IP += ADDRSZ; | 
|---|
| 191 | cev_check_dup_prim(); | 
|---|
| 192 | break; | 
|---|
| 193 | case kwTYPE_VAR: | 
|---|
| 194 | cev_prim_var(); | 
|---|
| 195 | cev_check_dup_prim(); | 
|---|
| 196 | break; | 
|---|
| 197 | case kwTYPE_CALL_UDF:        // [udf1][addr2] | 
|---|
| 198 | case kwTYPE_CALLEXTF:        // [lib][index] | 
|---|
| 199 | bc_add_n(bc_out, bc_in->ptr + bc_in->cp, ADDRSZ); | 
|---|
| 200 | IP += ADDRSZ;              // no break here | 
|---|
| 201 | case kwTYPE_CALLF:           // [code] | 
|---|
| 202 | bc_add_n(bc_out, bc_in->ptr + bc_in->cp, ADDRSZ); | 
|---|
| 203 | IP += ADDRSZ;              // no break here | 
|---|
| 204 | default: | 
|---|
| 205 | if (CODE_PEEK() == kwTYPE_LEVEL_BEGIN) { | 
|---|
| 206 | if (CODE(IP + 1) == kwTYPE_LEVEL_END) { | 
|---|
| 207 | cev_empty_args(); | 
|---|
| 208 | } else { | 
|---|
| 209 | cev_prim_args(); | 
|---|
| 210 | } | 
|---|
| 211 | } | 
|---|
| 212 | if (code != kwBYREF) { | 
|---|
| 213 | cev_check_dup_prim(); | 
|---|
| 214 | } | 
|---|
| 215 | break; | 
|---|
| 216 | }; | 
|---|
| 217 | } | 
|---|
| 218 |  | 
|---|
| 219 | /* | 
|---|
| 220 | * parenthesis | 
|---|
| 221 | */ | 
|---|
| 222 | void cev_parenth() { | 
|---|
| 223 | IF_ERR_RTN; | 
|---|
| 224 | if (CODE_PEEK() == kwTYPE_LEVEL_BEGIN) { | 
|---|
| 225 | if (CODE(IP + 1) == kwTYPE_LEVEL_END) { | 
|---|
| 226 | cev_empty_args(); | 
|---|
| 227 | } else { | 
|---|
| 228 | cev_prim_args(); | 
|---|
| 229 | } | 
|---|
| 230 | } else { | 
|---|
| 231 | cev_prim(); | 
|---|
| 232 | } | 
|---|
| 233 | } | 
|---|
| 234 |  | 
|---|
| 235 | /* | 
|---|
| 236 | * unary | 
|---|
| 237 | */ | 
|---|
| 238 | void cev_unary() { | 
|---|
| 239 | char op; | 
|---|
| 240 |  | 
|---|
| 241 | IF_ERR_RTN; | 
|---|
| 242 | if (CODE(IP) == kwTYPE_UNROPR || CODE(IP) == kwTYPE_ADDOPR) { | 
|---|
| 243 | op = CODE(IP + 1); | 
|---|
| 244 | IP += 2; | 
|---|
| 245 | } else { | 
|---|
| 246 | op = 0; | 
|---|
| 247 | } | 
|---|
| 248 | cev_parenth();        // R = cev_parenth | 
|---|
| 249 | if (op) { | 
|---|
| 250 | cev_add1(kwTYPE_UNROPR); | 
|---|
| 251 | cev_add1(op);       // R = op R | 
|---|
| 252 | } | 
|---|
| 253 | } | 
|---|
| 254 |  | 
|---|
| 255 | /* | 
|---|
| 256 | * pow | 
|---|
| 257 | */ | 
|---|
| 258 | void cev_pow() { | 
|---|
| 259 | cev_unary();                  // R = cev_unary | 
|---|
| 260 |  | 
|---|
| 261 | IF_ERR_RTN; | 
|---|
| 262 | while (CODE(IP) == kwTYPE_POWOPR) { | 
|---|
| 263 | IP += 2; | 
|---|
| 264 |  | 
|---|
| 265 | cev_add1(kwTYPE_EVPUSH);    // PUSH R | 
|---|
| 266 | cev_unary();                // R = cev_unary | 
|---|
| 267 | IF_ERR_RTN; | 
|---|
| 268 | cev_add1(kwTYPE_EVPOP);     // POP LEFT | 
|---|
| 269 | cev_add2(kwTYPE_POWOPR, '^'); // R = LEFT op R | 
|---|
| 270 | } | 
|---|
| 271 | } | 
|---|
| 272 |  | 
|---|
| 273 | /* | 
|---|
| 274 | * mul | div | mod | 
|---|
| 275 | */ | 
|---|
| 276 | void cev_mul() { | 
|---|
| 277 | cev_pow();                    // R = cev_pow() | 
|---|
| 278 |  | 
|---|
| 279 | IF_ERR_RTN; | 
|---|
| 280 | while (CODE(IP) == kwTYPE_MULOPR) { | 
|---|
| 281 | char op; | 
|---|
| 282 |  | 
|---|
| 283 | op = CODE(++IP); | 
|---|
| 284 | IP++; | 
|---|
| 285 | cev_add1(kwTYPE_EVPUSH);    // PUSH R | 
|---|
| 286 |  | 
|---|
| 287 | cev_pow(); | 
|---|
| 288 | IF_ERR_RTN; | 
|---|
| 289 | cev_add1(kwTYPE_EVPOP);      // POP LEFT | 
|---|
| 290 | cev_add2(kwTYPE_MULOPR, op); // R = LEFT op R | 
|---|
| 291 | } | 
|---|
| 292 | } | 
|---|
| 293 |  | 
|---|
| 294 | /* | 
|---|
| 295 | * add | sub | 
|---|
| 296 | */ | 
|---|
| 297 | void cev_add() { | 
|---|
| 298 | cev_mul();                    // R = cev_mul() | 
|---|
| 299 |  | 
|---|
| 300 | IF_ERR_RTN; | 
|---|
| 301 | while (CODE(IP) == kwTYPE_ADDOPR) { | 
|---|
| 302 | char op; | 
|---|
| 303 |  | 
|---|
| 304 | IP++; | 
|---|
| 305 | op = CODE(IP); | 
|---|
| 306 | IP++; | 
|---|
| 307 | cev_add1(kwTYPE_EVPUSH);    // PUSH R | 
|---|
| 308 |  | 
|---|
| 309 | cev_mul();                  // R = cev_mul | 
|---|
| 310 | IF_ERR_RTN; | 
|---|
| 311 |  | 
|---|
| 312 | cev_add1(kwTYPE_EVPOP);    // POP LEFT | 
|---|
| 313 | cev_add2(kwTYPE_ADDOPR, op); // R = LEFT op R | 
|---|
| 314 | } | 
|---|
| 315 | } | 
|---|
| 316 |  | 
|---|
| 317 | /* | 
|---|
| 318 | * compare | 
|---|
| 319 | */ | 
|---|
| 320 | void cev_cmp() { | 
|---|
| 321 | cev_add();                    // R = cev_add() | 
|---|
| 322 |  | 
|---|
| 323 | IF_ERR_RTN; | 
|---|
| 324 | while (CODE(IP) == kwTYPE_CMPOPR) { | 
|---|
| 325 | char op; | 
|---|
| 326 |  | 
|---|
| 327 | IP++; | 
|---|
| 328 | op = CODE(IP); | 
|---|
| 329 | IP++; | 
|---|
| 330 | cev_add1(kwTYPE_EVPUSH);    // PUSH R | 
|---|
| 331 | cev_add();                  // R = cev_add() | 
|---|
| 332 | IF_ERR_RTN; | 
|---|
| 333 | cev_add1(kwTYPE_EVPOP);         // POP LEFT | 
|---|
| 334 | cev_add2(kwTYPE_CMPOPR, op);    // R = LEFT op R | 
|---|
| 335 | } | 
|---|
| 336 | } | 
|---|
| 337 |  | 
|---|
| 338 | /* | 
|---|
| 339 | * logical | 
|---|
| 340 | */ | 
|---|
| 341 | void cev_log(void) { | 
|---|
| 342 | cev_cmp();                    // R = cev_cmp() | 
|---|
| 343 | IF_ERR_RTN; | 
|---|
| 344 | while (CODE(IP) == kwTYPE_LOGOPR) { | 
|---|
| 345 | byte op; | 
|---|
| 346 | bcip_t shortcut; | 
|---|
| 347 | bcip_t shortcut_offs; | 
|---|
| 348 |  | 
|---|
| 349 | IP++; | 
|---|
| 350 | op = CODE(IP); | 
|---|
| 351 | IP++; | 
|---|
| 352 |  | 
|---|
| 353 | cev_add1(kwTYPE_EVPUSH);    // PUSH R (push the left side result | 
|---|
| 354 | cev_add1(kwTYPE_EVAL_SC); | 
|---|
| 355 | cev_add2(kwTYPE_LOGOPR, op); | 
|---|
| 356 | shortcut = bc_out->count;   // shortcut jump target (calculated below) | 
|---|
| 357 | cev_add_addr(0); | 
|---|
| 358 |  | 
|---|
| 359 | cev_cmp();                  // right seg // R = cev_cmp() | 
|---|
| 360 | IF_ERR_RTN; | 
|---|
| 361 | cev_add1(kwTYPE_EVPOP);    // POP LEFT | 
|---|
| 362 | cev_add2(kwTYPE_LOGOPR, op); // R = LEFT op R | 
|---|
| 363 |  | 
|---|
| 364 | shortcut_offs = bc_out->count - shortcut; | 
|---|
| 365 | memcpy(bc_out->ptr + shortcut, &shortcut_offs, ADDRSZ); | 
|---|
| 366 | } | 
|---|
| 367 | } | 
|---|
| 368 |  | 
|---|
| 369 | /* | 
|---|
| 370 | * main | 
|---|
| 371 | */ | 
|---|
| 372 | void expr_parser(bc_t *bc_src) { | 
|---|
| 373 | // init | 
|---|
| 374 | bc_in = bc_src; | 
|---|
| 375 | bc_out = malloc(sizeof(bc_t)); | 
|---|
| 376 | bc_create(bc_out); | 
|---|
| 377 |  | 
|---|
| 378 | byte code = CODE_PEEK(); | 
|---|
| 379 |  | 
|---|
| 380 | // | 
|---|
| 381 | // empty! | 
|---|
| 382 | // | 
|---|
| 383 | if (code == kwTYPE_LINE || code == kwTYPE_EOC) { | 
|---|
| 384 | bc_destroy(bc_out); | 
|---|
| 385 | free(bc_out); | 
|---|
| 386 | return; | 
|---|
| 387 | } | 
|---|
| 388 | // | 
|---|
| 389 | // LET|CONST special code | 
|---|
| 390 | // | 
|---|
| 391 | if (code == kwTYPE_CMPOPR) { | 
|---|
| 392 | IP++; | 
|---|
| 393 | if (CODE(IP) != '=') { | 
|---|
| 394 | cev_opr_err(); | 
|---|
| 395 | bc_destroy(bc_out); | 
|---|
| 396 | free(bc_out); | 
|---|
| 397 | return; | 
|---|
| 398 | } else { | 
|---|
| 399 | IP++; | 
|---|
| 400 | cev_add2(kwTYPE_CMPOPR, '='); | 
|---|
| 401 | } | 
|---|
| 402 | } | 
|---|
| 403 | // start | 
|---|
| 404 | code = CODE_PEEK(); | 
|---|
| 405 | while (code != kwTYPE_EOC && code != kwTYPE_LINE && !comp_error) { | 
|---|
| 406 | if (kw_check_evexit(code)) {  // separator | 
|---|
| 407 | cev_add1(code); | 
|---|
| 408 | IP++;                     // add sep. | 
|---|
| 409 | if (code == kwUSE) { | 
|---|
| 410 | cev_add_addr(0); | 
|---|
| 411 | // USE needs 2 ips | 
|---|
| 412 | cev_add_addr(0); | 
|---|
| 413 | IP += (ADDRSZ + ADDRSZ); | 
|---|
| 414 | } else if (code == kwAS) { | 
|---|
| 415 | if (CODE_PEEK() == kwTYPE_SEP) {  // OPEN ... AS #1 | 
|---|
| 416 | cev_add1(kwTYPE_SEP); | 
|---|
| 417 | IP++; | 
|---|
| 418 | cev_add1(CODE(IP)); | 
|---|
| 419 | IP++; | 
|---|
| 420 | } | 
|---|
| 421 | } else { | 
|---|
| 422 | if (code == kwTYPE_SEP) { // Normal separator (,;) | 
|---|
| 423 | cev_add1(CODE(IP)); | 
|---|
| 424 | IP++; | 
|---|
| 425 | } | 
|---|
| 426 | } | 
|---|
| 427 | code = CODE_PEEK();       // next | 
|---|
| 428 | continue; | 
|---|
| 429 | } | 
|---|
| 430 | cev_log();                  // do it | 
|---|
| 431 | code = CODE_PEEK();         // next | 
|---|
| 432 | } | 
|---|
| 433 |  | 
|---|
| 434 | // finish | 
|---|
| 435 | if (bc_out->count) { | 
|---|
| 436 | bc_in->count = 0; | 
|---|
| 437 | bc_append(bc_in, bc_out); | 
|---|
| 438 | } | 
|---|
| 439 |  | 
|---|
| 440 | bc_destroy(bc_out); | 
|---|
| 441 | free(bc_out); | 
|---|
| 442 | } | 
|---|
| 443 |  | 
|---|