From 815b88e50fc72baf3a9baa34910cdf063b264ee2 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Wed, 14 Jan 2015 11:59:39 -0800 Subject: [PATCH] Complete contant expression evaluation --- src/samplesrc/test.pla | 6 + src/toolsrc/parse.c | 247 +++++++++++++++++++++++----------- src/toolsrc/sb.pla | 292 +++++++++++++++++++++++------------------ src/vmsrc/a1cmd.pla | 2 +- src/vmsrc/cmd.pla | 2 +- src/vmsrc/soscmd.pla | 2 +- 6 files changed, 346 insertions(+), 205 deletions(-) diff --git a/src/samplesrc/test.pla b/src/samplesrc/test.pla index e2cb994..e815673 100755 --- a/src/samplesrc/test.pla +++ b/src/samplesrc/test.pla @@ -13,6 +13,10 @@ struc mystruc word data end // +// Const expression +// +const constval = 2*(2+3) // a test expression should evaluate to 10 +// // Declare all global variables for this module. // Note that arrays are declared with prefix []. postfix [], or no []. // Only arrays with predclared sizes need [ and ], such as "int[3] a". @@ -24,6 +28,7 @@ byte[] a2p = "][+" byte[] a2e = "//e" byte[] a2c = "//c" byte[] a3 = "///" +byte constr = "Constant expression = " byte[] offsets = "Structure offsets:" word array[] = 1, 10, 100, 1000, 10000 word ptr @@ -108,4 +113,5 @@ puti(data) putln puti(mystruc) putln +puts(@constr); puti(constval); putln done diff --git a/src/toolsrc/parse.c b/src/toolsrc/parse.c index f85bc4c..fd3ec75 100755 --- a/src/toolsrc/parse.c +++ b/src/toolsrc/parse.c @@ -67,9 +67,87 @@ int tos_op_prec(int tos) { return opsptr <= tos ? 100 : precstack[opsptr]; } +long valstack[16]; +int typestack[16]; +int sizestack[16]; +int valptr = -1; +void push_val(long value, int size, int type) +{ + if (++valptr == 16) + { + parse_error("Stack overflow\n"); + return; + } + valstack[valptr] = value; + sizestack[valptr] = size; + typestack[valptr] = type; +} +int pop_val(long *value, int *size, int *type) +{ + if (valptr < 0) + { + parse_error("Stack underflow\n"); + return (-1); + } + *value = valstack[valptr]; + *size = sizestack[valptr]; + *type = typestack[valptr]; + return valptr--; +} /* * Constant expression parsing */ +int calc_op(t_token op) +{ + long val1, val2; + int size1, size2, type1, type2; + if (!pop_val(&val2, &size2, &type2)) + return 0; + pop_val(&val1, &size1, &type1); + if (type1 != CONST_TYPE || type2 != CONST_TYPE) + { + parse_error("Bad constant operand"); + return (0); + } + switch (op) + { + case MUL_TOKEN: + val1 *= val2; + break; + case DIV_TOKEN: + val1 /= val2; + break; + case MOD_TOKEN: + val1 %= val2; + break; + case ADD_TOKEN: + val1 += val2; + break; + case SUB_TOKEN: + val1 -= val2; + break; + case SHL_TOKEN: + val1 <<= val2; + break; + case SHR_TOKEN: + val1 >>= val2; + break; + case AND_TOKEN: + val1 &= val2; + break; + case OR_TOKEN: + val1 |= val2; + break; + case EOR_TOKEN: + val1 ^= val2; + break; + default: + return (0); + } + size1 = size1 > size2 ? size1 : size2; + push_val(val1, size1, type1); + return (1); +} int parse_constexpr(long *value, int *size); int parse_constterm(long *value, int *size) { @@ -104,11 +182,14 @@ int parse_constterm(long *value, int *size) } return (type); } -int parse_constval(long *value, int *size) +int parse_constval(void) { - int mod = 0, type; + int mod = 0, type, size; + long value; - while (!(type = parse_constterm(value, size))) + value = 0; + size = 1; + while (!(type = parse_constterm(&value, &size))) { switch (scantoken) { @@ -138,10 +219,12 @@ int parse_constval(long *value, int *size) */ switch (scantoken) { + case CLOSE_PAREN_TOKEN: + break; case STRING_TOKEN: - *size = tokenlen - 1; - *value = constval; - type = STRING_TYPE; + size = tokenlen - 1; + value = constval; + type = STRING_TYPE; if (mod) { parse_error("Invalid string modifiers"); @@ -149,100 +232,110 @@ int parse_constval(long *value, int *size) } break; case CHAR_TOKEN: - *size = 1; - *value = constval; - type = CONST_TYPE; + size = 1; + value = constval; + type = CONST_TYPE; break; case INT_TOKEN: - *size = 2; - *value = constval; - type = CONST_TYPE; + size = 2; + value = constval; + type = CONST_TYPE; break; case ID_TOKEN: - *size = 2; + size = 2; type = id_type(tokenstr, tokenlen); if (type & CONST_TYPE) - *value = id_const(tokenstr, tokenlen); + value = id_const(tokenstr, tokenlen); else if ((type & (FUNC_TYPE | EXTERN_TYPE)) || ((type & ADDR_TYPE) && (mod == 8))) - *value = id_tag(tokenstr, tokenlen); + value = id_tag(tokenstr, tokenlen); else - { - parse_error("Invalid constant"); return (0); - } - break; - case CLOSE_PAREN_TOKEN: break; default: - parse_error("Invalid constant"); return (0); } if (mod & 1) - *value = -*value; + value = -value; if (mod & 2) - *value = ~*value; + value = ~value; if (mod & 4) - *value = *value ? 0 : -1; + value = value ? 0 : -1; + push_val(value, size, type); return (type); } int parse_constexpr(long *value, int *size) { - long val1, val2; - int valtype, type, size1, size2; - - if (!(valtype = parse_constval(&val1, &size1))) - return (0); + int prevmatch; + int matchop = 0; + int optos = opsptr; + int i; + int type = CONST_TYPE; + *value = 0; + *size = 1; do { - size2 = 0; - switch (scan()) + /* + * Parse sequence of double operand operations. + */ + prevmatch = matchop; + matchop = 0; + if (parse_constval()) { - case ADD_TOKEN: - if (!(type = parse_constval(&val2, &size2))) - return (0); - val1 = val1 + val2; - break; - case SUB_TOKEN: - if (!(type = parse_constval(&val2, &size2))) - return (0); - val1 = val1 - val2; - break; - case MUL_TOKEN: - if (!(type = parse_constval(&val2, &size2))) - return (0); - val1 = val1 * val2; - break; - case DIV_TOKEN: - if (!(type = parse_constval(&val2, &size2))) - return (0); - val1 = val1 / val2; - break; - case AND_TOKEN: - if (!(type = parse_constval(&val2, &size2))) - return (0); - val1 = val1 & val2; - break; - case OR_TOKEN: - if (!(type = parse_constval(&val2, &size2))) - return (0); - val1 = val1 | val2; - break; - case EOR_TOKEN: - if (!(type = parse_constval(&val2, &size2))) - return (0); - val1 = val1 ^ val2; - break; + matchop = 1; + scan(); + for (i = 0; i < sizeof(binary_ops_table); i++) + if (scantoken == binary_ops_table[i]) + { + matchop = 2; + if (binary_ops_precedence[i] >= tos_op_prec(optos)) + if (!calc_op(pop_op())) + { + parse_error(": Invalid binary operation"); + return (0); + } + push_op(scantoken, binary_ops_precedence[i]); + break; + } } - if (size1 > size2) - *size = size1; - else + } while (matchop == 2); + if (matchop == 0 && prevmatch == 0) + return (0); + if (matchop == 0 && prevmatch == 2) + { + parse_error("Missing operand"); + return (0); + } + while (optos < opsptr) + if (!calc_op(pop_op())) { - valtype = type; - *size = size2; + parse_error(": Invalid binary operation"); + return (0); } - } while (size2); - *value = val1; - return (valtype); + pop_val(value, size, &type); + return (type); +} +int parse_const(long *value) +{ + /* + * Get simple constant. + */ + switch (scan()) + { + case CHAR_TOKEN: + case INT_TOKEN: + *value = constval; + break; + case ID_TOKEN: + if (id_type(tokenstr, tokenlen) & CONST_TYPE) + { + *value = id_const(tokenstr, tokenlen); + break; + } + default: + *value = 0; + return (0); + } + return (CONST_TYPE); } /* * Normal expression parsing @@ -509,7 +602,7 @@ int parse_value(int rvalue) } ref_type = (scantoken == PTRB_TOKEN) ? BPTR_TYPE : WPTR_TYPE; ref_offset = 0; - if (!parse_constval(&ref_offset, &const_size)) + if (!parse_const(&ref_offset)) scan_rewind(tokenstr); if (ref_offset != 0) { @@ -526,7 +619,7 @@ int parse_value(int rvalue) ref_type = (ref_type & (VAR_TYPE | CONST_TYPE)) ? ((scantoken == DOT_TOKEN) ? BYTE_TYPE : WORD_TYPE) : ((scantoken == DOT_TOKEN) ? BPTR_TYPE : WPTR_TYPE); - if (parse_constval(&const_offset, &const_size)) + if (parse_const(&const_offset)) ref_offset += const_offset; else scan_rewind(tokenstr); @@ -943,7 +1036,7 @@ int parse_stmnt(void) */ int elem_size; elem_type = (scantoken == DOT_TOKEN) ? BYTE_TYPE : WORD_TYPE; - if (!parse_constval(&elem_offset, &elem_size)) + if (!parse_const(&elem_offset)) scantoken = ID_TOKEN; else scan(); diff --git a/src/toolsrc/sb.pla b/src/toolsrc/sb.pla index bb3bab8..dd8e3d7 100644 --- a/src/toolsrc/sb.pla +++ b/src/toolsrc/sb.pla @@ -91,7 +91,7 @@ word = $0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0 // Editor variables // byte nullstr = "" -byte version = "PLASMA ][ SANDBOX VERSION 00.11 " +byte version = "PLASMA ][ SANDBOX VERSION 00.12" byte errorstr = "ERROR: $" byte okstr = "OK" byte outofmem = "OUT OF MEMORY!" @@ -287,6 +287,10 @@ byte = 10 byte[16] opstack byte[16] precstack word opsp = -1 +word[16] valstack +byte[16] sizestack +byte[16] typestack +word valsp = -1 // // Symbol table variables // @@ -327,9 +331,7 @@ word lineno = 0 // // Compiler output messages // -//byte entrypt_str[] = "START: " byte bytes_compiled_str[] = "\nBYTES COMPILED: " -//byte comp_ok_msg[] = "COMPILATION COMPLETE" byte dup_id[] = "DUPLICATE IDENTIFIER" byte undecl_id[] = "UNDECLARED IDENTIFIER" byte bad_cnst[] = "BAD CONSTANT" @@ -626,7 +628,7 @@ end // asm cout LDA ESTKL,X - BIT $BF98 +COUT1 BIT $BF98 BMI + JSR TOUPR + ORA #$80 @@ -663,17 +665,11 @@ asm prstr LDA (SRC),Y STA TMP BEQ ++ - BIT ROMEN - INY LDA (SRC),Y - BIT $BF98 - BMI + - JSR TOUPR -+ ORA #$80 - JSR $FDED + JSR COUT1 CPY TMP BNE - - BIT LCRDEN+LCBNK2 ++ RTS end // @@ -1282,35 +1278,21 @@ def drawscrn(toprow, ofst) byte row, numchars word strptr, scrnptr - if ofst - for row = 0 to 23 - strptr = strlinbuf:[toprow + row] - scrnptr = txtscrn[row] - if ofst >= ^strptr - numchars = 0 - else - numchars = ^strptr - ofst - fin - if numchars >= 40 - numchars = 40 - else - memset(scrnptr + numchars, 40 - numchars, $A0A0) - fin - memcpy(scrnptr, strptr + ofst + 1, numchars) - next - else - for row = 0 to 23 - strptr = strlinbuf:[toprow + row] - scrnptr = txtscrn[row] - numchars = ^strptr - if numchars >= 40 - numchars = 40 - else - memset(scrnptr + numchars, 40 - numchars, $A0A0) - fin - memcpy(scrnptr, strptr + 1, numchars) - next - fin + for row = 0 to 23 + strptr = strlinbuf:[toprow + row] + scrnptr = txtscrn[row] + if ofst >= ^strptr + numchars = 0 + else + numchars = ^strptr - ofst + fin + if numchars >= 40 + numchars = 40 + else + memset(scrnptr + numchars, 40 - numchars, $A0A0) + fin + memcpy(scrnptr, strptr + ofst + 1, numchars) + next end def cursoff if flags & showcurs @@ -1473,7 +1455,7 @@ def keyin2e key = keyctrlz break is keyenter - key = keyctrlo + key = keyctrlf break wend fin @@ -2625,6 +2607,25 @@ def tos_op_prec(tos) fin return precstack[opsp] end +def push_val(value, size, type) + valsp = valsp + 1 + if valsp == 16 + return parse_err(@estk_overflw) + fin + valstack[valsp] = value + sizestack[valsp] = size + typestack[valsp] = type +end +def pop_val(valptr, sizeptr, typeptr) + if valsp < 0 + return parse_err(@estk_underflw) + fin + *valptr = valstack[valsp] + ^sizeptr = sizestack[valsp] + ^typeptr = typestack[valsp] + valsp = valsp - 1 + return valsp + 1 +end // // Lexical anaylzer // @@ -2868,12 +2869,57 @@ end // // Constant expression parsing // +def calc_binaryop(op) + word val1, val2 + byte size1, size2, type1, type2 + + if not pop_val(@val2, @size2, @type2); return 0; fin + pop_val(@val1, @size1, @type1) + if type1 <> CONST_TYPE and type2 <> CONST_TYPE; return parse_err(@bad_cnst); fin + when op + is MUL_TKN + val1 = val1 * val2 + break + is DIV_TKN + val1 = val1 / val2 + break + is MOD_TKN + val1 = val1 % val2 + break + is ADD_TKN + val1 = val1 + val2 + break + is SUB_TKN + val1 = val1 - val2 + break + is SHL_TKN + val1 = val1 << val2 + break + is SHR_TKN + val1 = val1 >> val2 + break + is AND_TKN + val1 = val1 & val2 + break + is OR_TKN + val1 = val1 | val2 + break + is EOR_TKN + val1 = val1 ^ val2 + break + otherwise + return FALSE + wend + if size2 > size1; size1 = size2; fin + push_val(val1, size1, type1) + return TRUE +end def parse_constterm(valptr, sizeptr) word type when scan is OPEN_PAREN_TKN - type = parse_constexpr(valptr, sizeptr) + type = parse_constexpr(valptr, sizeptr) if token <> CLOSE_PAREN_TKN; return parse_err(@no_close_paren); fin return type is ID_TKN @@ -2884,14 +2930,15 @@ def parse_constterm(valptr, sizeptr) wend return FALSE end -def parse_constval(valptr, sizeptr) - byte mod, type - word idptr, ctag +def parse_constval + byte mod, type, size + word idptr, ctag, value - mod = 0 - ^sizeptr = 0 + value = 0 + size = 1 + mod = 0 repeat - type = parse_constterm(valptr, sizeptr) + type = parse_constterm(@value, @size) if !type when token is SUB_TKN @@ -2910,108 +2957,103 @@ def parse_constval(valptr, sizeptr) fin until type when token + is CLOSE_PAREN_TKN + break is STR_TKN - ^sizeptr = tknlen - 1 - *valptr = constval - type = STR_TYPE + size = tknlen - 1 + value = constval + type = STR_TYPE if mod; return parse_err(@bad_op); fin break is CHR_TKN - ^sizeptr = 1 - *valptr = constval - type = BYTE_TYPE + size = 1 + value = constval + type = CONST_TYPE break is INT_TKN - ^sizeptr = 2 - *valptr = constval - type = WORD_TYPE + size = 2 + value = constval + type = CONST_TYPE break is ID_TKN - ^sizeptr = 2 - idptr = id_lookup(tknptr, tknlen) + size = 2 + idptr = id_lookup(tknptr, tknlen) if !idptr; return parse_err(@bad_cnst); fin type = idptr->idtype if type & ADDR_TYPE - if mod <> 8; return parse_err(@bad_cnst); fin + if mod <> 8; return parse_err(@bad_cnst); fin type = CONSTADDR_TYPE fin - *valptr = idptr=>idval + value = idptr=>idval break - is CLOSE_PAREN_TKN - break otherwise - return parse_err(@bad_cnst) + return 0 wend if mod & 1 - *valptr = -*valptr + value = -value fin if mod & 2 - *valptr = ~*valptr + value = ~value fin if mod & 4 - *valptr = !*valptr + value = !value fin + push_val(value, size, type) return type end def parse_constexpr(valptr, sizeptr) - byte valtype, type, size1, size2 - word val1, val2 + byte prevmatch, matchop, i, type + word optos - valtype = parse_constval(@val1, @size1) - if !valtype; return 0; fin + *valptr = 0 + *sizeptr = 1 + matchop = 0 + optos = opsp repeat - size2 = 0 - when scan - is ADD_TKN - type = parse_constval(@val2, @size2) - if !type; return 0; fin - val1 = val1 + val2 - break - is SUB_TKN - type = parse_constval(@val2, @size2) - if !type; return 0; fin - val1 = val1 - val2 - break - is MUL_TKN - type = parse_constval(@val2, @size2) - if !type; return 0; fin - val1 = val1 * val2 - break - is DIV_TKN - type = parse_constval(@val2, @size2) - if !type; return 0; fin - val1 = val1 / val2 - break - is MOD_TKN - type = parse_constval(@val2, @size2) - if !type; return 0; fin - val1 = val1 % val2 - break - is AND_TKN - type = parse_constval(@val2, @size2) - if !type; return 0; fin - val1 = val1 & val2 - break - is OR_TKN - type = parse_constval(@val2, @size2) - if !type; return 0; fin - val1 = val1 | val2 - break - is EOR_TKN - type = parse_constval(@val2, @size2) - if !type; return 0; fin - val1 = val1 ^ val2 - break - wend - if size1 > size2 - ^sizeptr = size1 - else - valtype = type - ^sizeptr = size2 + prevmatch = matchop + matchop = 0 + if parse_constval + matchop = 1 + scan + for i = 0 to bops_tblsz + if token == bops_tbl[i] + matchop = 2 + if bops_prec[i] >= tos_op_prec(optos) + if !calc_binaryop(pop_op); return parse_err(@bad_op); fin + fin + push_op(token, bops_prec[i]) + break + fin + next fin - until !size2 - *valptr = val1 - return valtype + until matchop <> 2 + if matchop == 0 and prevmatch == 0; return 0; fin + if matchop == 0 and prevmatch == 2; return parse_err(@missing_op); fin + while optos < opsp + if !calc_binaryop(pop_op); return parse_err(@bad_op); fin + loop + pop_val(valptr, sizeptr, @type) + return type +end +def parse_const(valptr) + word idptr + + when scan + is CHR_TKN + is INT_TKN + *valptr = constval + break + is ID_TKN + idptr = id_lookup(tknptr, tknlen) + if !idptr; return parse_err(@bad_cnst); fin + if idptr->idtype & CONST_TYPE + *valptr = idptr=>idval + break + fin + otherwise + return 0 + wend + return CONST_TYPE end // // Normal expression parsing @@ -3255,7 +3297,7 @@ def parse_value(rvalue) ref_type = WPTR_TYPE fin ref_offset = 0 - if !parse_constval(@ref_offset, @const_size) + if !parse_const(@ref_offset) rewind(tknptr) fin if ref_offset <> 0 @@ -3282,7 +3324,7 @@ def parse_value(rvalue) ref_type = WPTR_TYPE fin fin - if parse_constval(@const_offset, @const_size) + if parse_const(@const_offset) ref_offset = ref_offset + const_offset else rewind(tknptr) @@ -3640,7 +3682,7 @@ def parse_stmnt else elem_type = WORD_TYPE fin - if !parse_constval(@elem_offset, @elem_size) + if !parse_const(@elem_offset) token = ID_TKN else scan diff --git a/src/vmsrc/a1cmd.pla b/src/vmsrc/a1cmd.pla index 4d35470..6e3ecf8 100644 --- a/src/vmsrc/a1cmd.pla +++ b/src/vmsrc/a1cmd.pla @@ -39,7 +39,7 @@ predef loadmod, execmod, lookupstrmod // // System variables. // -word version = $0011 // 00.1 +word version = $0012 // 00.12 word systemflags = 0 word heap word symtbl, lastsym diff --git a/src/vmsrc/cmd.pla b/src/vmsrc/cmd.pla index 27baf44..2db94b5 100644 --- a/src/vmsrc/cmd.pla +++ b/src/vmsrc/cmd.pla @@ -33,7 +33,7 @@ predef loadmod, execmod, lookupstrmod // // System variable. // -word version = $0011 // 00.11 +word version = $0012 // 00.12 word systemflags = 0 word heap word xheap = $0800 diff --git a/src/vmsrc/soscmd.pla b/src/vmsrc/soscmd.pla index 1012569..73b9f3e 100644 --- a/src/vmsrc/soscmd.pla +++ b/src/vmsrc/soscmd.pla @@ -34,7 +34,7 @@ predef loadmod, execmod, lookupstrmod // // System variables. // -word version = $0011 // 00.11 +word version = $0012 // 00.12 word systemflags = 0 byte refcons = 0 byte devcons = 0