1
0
mirror of https://github.com/dschmenk/PLASMA.git synced 2024-07-05 04:28:57 +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
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

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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