1
0
mirror of https://github.com/dschmenk/PLASMA.git synced 2024-10-04 03:59:49 +00:00

Complete contant expression evaluation

This commit is contained in:
David Schmenk 2015-01-14 11:59:39 -08:00
parent 3a7a804f9b
commit 815b88e50f
6 changed files with 346 additions and 205 deletions

View File

@ -13,6 +13,10 @@ struc mystruc
word data word data
end end
// //
// Const expression
//
const constval = 2*(2+3) // a test expression should evaluate to 10
//
// Declare all global variables for this module. // Declare all global variables for this module.
// Note that arrays are declared with prefix []. postfix [], or no []. // Note that arrays are declared with prefix []. postfix [], or no [].
// Only arrays with predclared sizes need [ and ], such as "int[3] a". // Only arrays with predclared sizes need [ and ], such as "int[3] a".
@ -24,6 +28,7 @@ byte[] a2p = "][+"
byte[] a2e = "//e" byte[] a2e = "//e"
byte[] a2c = "//c" byte[] a2c = "//c"
byte[] a3 = "///" byte[] a3 = "///"
byte constr = "Constant expression = "
byte[] offsets = "Structure offsets:" byte[] offsets = "Structure offsets:"
word array[] = 1, 10, 100, 1000, 10000 word array[] = 1, 10, 100, 1000, 10000
word ptr word ptr
@ -108,4 +113,5 @@ puti(data)
putln putln
puti(mystruc) puti(mystruc)
putln putln
puts(@constr); puti(constval); putln
done done

View File

@ -67,9 +67,87 @@ int tos_op_prec(int tos)
{ {
return opsptr <= tos ? 100 : precstack[opsptr]; 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 * 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_constexpr(long *value, int *size);
int parse_constterm(long *value, int *size) int parse_constterm(long *value, int *size)
{ {
@ -104,11 +182,14 @@ int parse_constterm(long *value, int *size)
} }
return (type); 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) switch (scantoken)
{ {
@ -138,10 +219,12 @@ int parse_constval(long *value, int *size)
*/ */
switch (scantoken) switch (scantoken)
{ {
case CLOSE_PAREN_TOKEN:
break;
case STRING_TOKEN: case STRING_TOKEN:
*size = tokenlen - 1; size = tokenlen - 1;
*value = constval; value = constval;
type = STRING_TYPE; type = STRING_TYPE;
if (mod) if (mod)
{ {
parse_error("Invalid string modifiers"); parse_error("Invalid string modifiers");
@ -149,100 +232,110 @@ int parse_constval(long *value, int *size)
} }
break; break;
case CHAR_TOKEN: case CHAR_TOKEN:
*size = 1; size = 1;
*value = constval; value = constval;
type = CONST_TYPE; type = CONST_TYPE;
break; break;
case INT_TOKEN: case INT_TOKEN:
*size = 2; size = 2;
*value = constval; value = constval;
type = CONST_TYPE; type = CONST_TYPE;
break; break;
case ID_TOKEN: case ID_TOKEN:
*size = 2; size = 2;
type = id_type(tokenstr, tokenlen); type = id_type(tokenstr, tokenlen);
if (type & CONST_TYPE) 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))) else if ((type & (FUNC_TYPE | EXTERN_TYPE)) || ((type & ADDR_TYPE) && (mod == 8)))
*value = id_tag(tokenstr, tokenlen); value = id_tag(tokenstr, tokenlen);
else else
{
parse_error("Invalid constant");
return (0); return (0);
}
break;
case CLOSE_PAREN_TOKEN:
break; break;
default: default:
parse_error("Invalid constant");
return (0); return (0);
} }
if (mod & 1) if (mod & 1)
*value = -*value; value = -value;
if (mod & 2) if (mod & 2)
*value = ~*value; value = ~value;
if (mod & 4) if (mod & 4)
*value = *value ? 0 : -1; value = value ? 0 : -1;
push_val(value, size, type);
return (type); return (type);
} }
int parse_constexpr(long *value, int *size) int parse_constexpr(long *value, int *size)
{ {
long val1, val2; int prevmatch;
int valtype, type, size1, size2; int matchop = 0;
int optos = opsptr;
if (!(valtype = parse_constval(&val1, &size1))) int i;
return (0); int type = CONST_TYPE;
*value = 0;
*size = 1;
do do
{ {
size2 = 0; /*
switch (scan()) * Parse sequence of double operand operations.
*/
prevmatch = matchop;
matchop = 0;
if (parse_constval())
{ {
case ADD_TOKEN: matchop = 1;
if (!(type = parse_constval(&val2, &size2))) scan();
return (0); for (i = 0; i < sizeof(binary_ops_table); i++)
val1 = val1 + val2; if (scantoken == binary_ops_table[i])
break; {
case SUB_TOKEN: matchop = 2;
if (!(type = parse_constval(&val2, &size2))) if (binary_ops_precedence[i] >= tos_op_prec(optos))
return (0); if (!calc_op(pop_op()))
val1 = val1 - val2; {
break; parse_error(": Invalid binary operation");
case MUL_TOKEN: return (0);
if (!(type = parse_constval(&val2, &size2))) }
return (0); push_op(scantoken, binary_ops_precedence[i]);
val1 = val1 * val2; break;
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;
} }
if (size1 > size2) } while (matchop == 2);
*size = size1; if (matchop == 0 && prevmatch == 0)
else return (0);
if (matchop == 0 && prevmatch == 2)
{
parse_error("Missing operand");
return (0);
}
while (optos < opsptr)
if (!calc_op(pop_op()))
{ {
valtype = type; parse_error(": Invalid binary operation");
*size = size2; return (0);
} }
} while (size2); pop_val(value, size, &type);
*value = val1; return (type);
return (valtype); }
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 * Normal expression parsing
@ -509,7 +602,7 @@ int parse_value(int rvalue)
} }
ref_type = (scantoken == PTRB_TOKEN) ? BPTR_TYPE : WPTR_TYPE; ref_type = (scantoken == PTRB_TOKEN) ? BPTR_TYPE : WPTR_TYPE;
ref_offset = 0; ref_offset = 0;
if (!parse_constval(&ref_offset, &const_size)) if (!parse_const(&ref_offset))
scan_rewind(tokenstr); scan_rewind(tokenstr);
if (ref_offset != 0) if (ref_offset != 0)
{ {
@ -526,7 +619,7 @@ int parse_value(int rvalue)
ref_type = (ref_type & (VAR_TYPE | CONST_TYPE)) ref_type = (ref_type & (VAR_TYPE | CONST_TYPE))
? ((scantoken == DOT_TOKEN) ? BYTE_TYPE : WORD_TYPE) ? ((scantoken == DOT_TOKEN) ? BYTE_TYPE : WORD_TYPE)
: ((scantoken == DOT_TOKEN) ? BPTR_TYPE : WPTR_TYPE); : ((scantoken == DOT_TOKEN) ? BPTR_TYPE : WPTR_TYPE);
if (parse_constval(&const_offset, &const_size)) if (parse_const(&const_offset))
ref_offset += const_offset; ref_offset += const_offset;
else else
scan_rewind(tokenstr); scan_rewind(tokenstr);
@ -943,7 +1036,7 @@ int parse_stmnt(void)
*/ */
int elem_size; int elem_size;
elem_type = (scantoken == DOT_TOKEN) ? BYTE_TYPE : WORD_TYPE; elem_type = (scantoken == DOT_TOKEN) ? BYTE_TYPE : WORD_TYPE;
if (!parse_constval(&elem_offset, &elem_size)) if (!parse_const(&elem_offset))
scantoken = ID_TOKEN; scantoken = ID_TOKEN;
else else
scan(); scan();

View File

@ -91,7 +91,7 @@ word = $0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0
// Editor variables // Editor variables
// //
byte nullstr = "" byte nullstr = ""
byte version = "PLASMA ][ SANDBOX VERSION 00.11 " byte version = "PLASMA ][ SANDBOX VERSION 00.12"
byte errorstr = "ERROR: $" byte errorstr = "ERROR: $"
byte okstr = "OK" byte okstr = "OK"
byte outofmem = "OUT OF MEMORY!" byte outofmem = "OUT OF MEMORY!"
@ -287,6 +287,10 @@ byte = 10
byte[16] opstack byte[16] opstack
byte[16] precstack byte[16] precstack
word opsp = -1 word opsp = -1
word[16] valstack
byte[16] sizestack
byte[16] typestack
word valsp = -1
// //
// Symbol table variables // Symbol table variables
// //
@ -327,9 +331,7 @@ word lineno = 0
// //
// Compiler output messages // Compiler output messages
// //
//byte entrypt_str[] = "START: "
byte bytes_compiled_str[] = "\nBYTES COMPILED: " byte bytes_compiled_str[] = "\nBYTES COMPILED: "
//byte comp_ok_msg[] = "COMPILATION COMPLETE"
byte dup_id[] = "DUPLICATE IDENTIFIER" byte dup_id[] = "DUPLICATE IDENTIFIER"
byte undecl_id[] = "UNDECLARED IDENTIFIER" byte undecl_id[] = "UNDECLARED IDENTIFIER"
byte bad_cnst[] = "BAD CONSTANT" byte bad_cnst[] = "BAD CONSTANT"
@ -626,7 +628,7 @@ end
// //
asm cout asm cout
LDA ESTKL,X LDA ESTKL,X
BIT $BF98 COUT1 BIT $BF98
BMI + BMI +
JSR TOUPR JSR TOUPR
+ ORA #$80 + ORA #$80
@ -663,17 +665,11 @@ asm prstr
LDA (SRC),Y LDA (SRC),Y
STA TMP STA TMP
BEQ ++ BEQ ++
BIT ROMEN
- INY - INY
LDA (SRC),Y LDA (SRC),Y
BIT $BF98 JSR COUT1
BMI +
JSR TOUPR
+ ORA #$80
JSR $FDED
CPY TMP CPY TMP
BNE - BNE -
BIT LCRDEN+LCBNK2
++ RTS ++ RTS
end end
// //
@ -1282,35 +1278,21 @@ def drawscrn(toprow, ofst)
byte row, numchars byte row, numchars
word strptr, scrnptr word strptr, scrnptr
if ofst for row = 0 to 23
for row = 0 to 23 strptr = strlinbuf:[toprow + row]
strptr = strlinbuf:[toprow + row] scrnptr = txtscrn[row]
scrnptr = txtscrn[row] if ofst >= ^strptr
if ofst >= ^strptr numchars = 0
numchars = 0 else
else numchars = ^strptr - ofst
numchars = ^strptr - ofst fin
fin if numchars >= 40
if numchars >= 40 numchars = 40
numchars = 40 else
else memset(scrnptr + numchars, 40 - numchars, $A0A0)
memset(scrnptr + numchars, 40 - numchars, $A0A0) fin
fin memcpy(scrnptr, strptr + ofst + 1, numchars)
memcpy(scrnptr, strptr + ofst + 1, numchars) next
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
end end
def cursoff def cursoff
if flags & showcurs if flags & showcurs
@ -1473,7 +1455,7 @@ def keyin2e
key = keyctrlz key = keyctrlz
break break
is keyenter is keyenter
key = keyctrlo key = keyctrlf
break break
wend wend
fin fin
@ -2625,6 +2607,25 @@ def tos_op_prec(tos)
fin fin
return precstack[opsp] return precstack[opsp]
end 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 // Lexical anaylzer
// //
@ -2868,12 +2869,57 @@ end
// //
// Constant expression parsing // 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) def parse_constterm(valptr, sizeptr)
word type word type
when scan when scan
is OPEN_PAREN_TKN 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 if token <> CLOSE_PAREN_TKN; return parse_err(@no_close_paren); fin
return type return type
is ID_TKN is ID_TKN
@ -2884,14 +2930,15 @@ def parse_constterm(valptr, sizeptr)
wend wend
return FALSE return FALSE
end end
def parse_constval(valptr, sizeptr) def parse_constval
byte mod, type byte mod, type, size
word idptr, ctag word idptr, ctag, value
mod = 0 value = 0
^sizeptr = 0 size = 1
mod = 0
repeat repeat
type = parse_constterm(valptr, sizeptr) type = parse_constterm(@value, @size)
if !type if !type
when token when token
is SUB_TKN is SUB_TKN
@ -2910,108 +2957,103 @@ def parse_constval(valptr, sizeptr)
fin fin
until type until type
when token when token
is CLOSE_PAREN_TKN
break
is STR_TKN is STR_TKN
^sizeptr = tknlen - 1 size = tknlen - 1
*valptr = constval value = constval
type = STR_TYPE type = STR_TYPE
if mod; return parse_err(@bad_op); fin if mod; return parse_err(@bad_op); fin
break break
is CHR_TKN is CHR_TKN
^sizeptr = 1 size = 1
*valptr = constval value = constval
type = BYTE_TYPE type = CONST_TYPE
break break
is INT_TKN is INT_TKN
^sizeptr = 2 size = 2
*valptr = constval value = constval
type = WORD_TYPE type = CONST_TYPE
break break
is ID_TKN is ID_TKN
^sizeptr = 2 size = 2
idptr = id_lookup(tknptr, tknlen) idptr = id_lookup(tknptr, tknlen)
if !idptr; return parse_err(@bad_cnst); fin if !idptr; return parse_err(@bad_cnst); fin
type = idptr->idtype type = idptr->idtype
if type & ADDR_TYPE 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 type = CONSTADDR_TYPE
fin fin
*valptr = idptr=>idval value = idptr=>idval
break break
is CLOSE_PAREN_TKN
break
otherwise otherwise
return parse_err(@bad_cnst) return 0
wend wend
if mod & 1 if mod & 1
*valptr = -*valptr value = -value
fin fin
if mod & 2 if mod & 2
*valptr = ~*valptr value = ~value
fin fin
if mod & 4 if mod & 4
*valptr = !*valptr value = !value
fin fin
push_val(value, size, type)
return type return type
end end
def parse_constexpr(valptr, sizeptr) def parse_constexpr(valptr, sizeptr)
byte valtype, type, size1, size2 byte prevmatch, matchop, i, type
word val1, val2 word optos
valtype = parse_constval(@val1, @size1) *valptr = 0
if !valtype; return 0; fin *sizeptr = 1
matchop = 0
optos = opsp
repeat repeat
size2 = 0 prevmatch = matchop
when scan matchop = 0
is ADD_TKN if parse_constval
type = parse_constval(@val2, @size2) matchop = 1
if !type; return 0; fin scan
val1 = val1 + val2 for i = 0 to bops_tblsz
break if token == bops_tbl[i]
is SUB_TKN matchop = 2
type = parse_constval(@val2, @size2) if bops_prec[i] >= tos_op_prec(optos)
if !type; return 0; fin if !calc_binaryop(pop_op); return parse_err(@bad_op); fin
val1 = val1 - val2 fin
break push_op(token, bops_prec[i])
is MUL_TKN break
type = parse_constval(@val2, @size2) fin
if !type; return 0; fin next
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
fin fin
until !size2 until matchop <> 2
*valptr = val1 if matchop == 0 and prevmatch == 0; return 0; fin
return valtype 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 end
// //
// Normal expression parsing // Normal expression parsing
@ -3255,7 +3297,7 @@ def parse_value(rvalue)
ref_type = WPTR_TYPE ref_type = WPTR_TYPE
fin fin
ref_offset = 0 ref_offset = 0
if !parse_constval(@ref_offset, @const_size) if !parse_const(@ref_offset)
rewind(tknptr) rewind(tknptr)
fin fin
if ref_offset <> 0 if ref_offset <> 0
@ -3282,7 +3324,7 @@ def parse_value(rvalue)
ref_type = WPTR_TYPE ref_type = WPTR_TYPE
fin fin
fin fin
if parse_constval(@const_offset, @const_size) if parse_const(@const_offset)
ref_offset = ref_offset + const_offset ref_offset = ref_offset + const_offset
else else
rewind(tknptr) rewind(tknptr)
@ -3640,7 +3682,7 @@ def parse_stmnt
else else
elem_type = WORD_TYPE elem_type = WORD_TYPE
fin fin
if !parse_constval(@elem_offset, @elem_size) if !parse_const(@elem_offset)
token = ID_TKN token = ID_TKN
else else
scan scan

View File

@ -39,7 +39,7 @@ predef loadmod, execmod, lookupstrmod
// //
// System variables. // System variables.
// //
word version = $0011 // 00.1 word version = $0012 // 00.12
word systemflags = 0 word systemflags = 0
word heap word heap
word symtbl, lastsym word symtbl, lastsym

View File

@ -33,7 +33,7 @@ predef loadmod, execmod, lookupstrmod
// //
// System variable. // System variable.
// //
word version = $0011 // 00.11 word version = $0012 // 00.12
word systemflags = 0 word systemflags = 0
word heap word heap
word xheap = $0800 word xheap = $0800

View File

@ -34,7 +34,7 @@ predef loadmod, execmod, lookupstrmod
// //
// System variables. // System variables.
// //
word version = $0011 // 00.11 word version = $0012 // 00.12
word systemflags = 0 word systemflags = 0
byte refcons = 0 byte refcons = 0
byte devcons = 0 byte devcons = 0