mirror of
https://github.com/uffejakobsen/acme.git
synced 2024-11-25 07:31:52 +00:00
simplified state machine of expression parser
git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@253 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
89344d34ee
commit
be72f71faa
163
src/alu.c
163
src/alu.c
@ -180,7 +180,6 @@ static int arg_sp;
|
|||||||
enum alu_state {
|
enum alu_state {
|
||||||
STATE_EXPECT_ARG_OR_MONADIC_OP,
|
STATE_EXPECT_ARG_OR_MONADIC_OP,
|
||||||
STATE_EXPECT_DYADIC_OP,
|
STATE_EXPECT_DYADIC_OP,
|
||||||
STATE_TRY_TO_REDUCE_STACKS, // FIXME - get rid of this
|
|
||||||
STATE_MAX_GO_ON, // "border value" to find the stoppers:
|
STATE_MAX_GO_ON, // "border value" to find the stoppers:
|
||||||
STATE_ERROR, // error has occurred
|
STATE_ERROR, // error has occurred
|
||||||
STATE_END // standard end
|
STATE_END // standard end
|
||||||
@ -747,142 +746,131 @@ static int parse_octal_or_unpseudo(void) // now GotByte = '&'
|
|||||||
// expression parser
|
// expression parser
|
||||||
|
|
||||||
|
|
||||||
// handler for special operators like parentheses and start/end of expression:
|
// handler for special operators like parentheses and start/end of expression
|
||||||
// returns whether caller can remove "previous" operator from stack
|
#define PREVIOUS_ARGUMENT (arg_stack[arg_sp - 2])
|
||||||
static boolean handle_special_operator(struct expression *expression, enum op_id previous)
|
#define NEWEST_ARGUMENT (arg_stack[arg_sp - 1])
|
||||||
|
#define PREVIOUS_OPERATOR (op_stack[op_sp - 2])
|
||||||
|
#define NEWEST_OPERATOR (op_stack[op_sp - 1])
|
||||||
|
static void handle_special_operator(struct expression *expression, enum op_id previous)
|
||||||
{
|
{
|
||||||
// when this gets called, "current" operator is OPID_TERMINATOR
|
// when this gets called, "current" operator is OPID_TERMINATOR
|
||||||
switch (previous) {
|
switch (previous) {
|
||||||
case OPID_START_EXPRESSION:
|
case OPID_START_EXPRESSION:
|
||||||
// therefore we know we are done.
|
alu_state = STATE_END; // we are done
|
||||||
// don't touch "is_parenthesized", because start/end are obviously not "real" operators
|
// don't touch "is_parenthesized", because start/end are obviously not "real" operators
|
||||||
alu_state = STATE_END; // done
|
// not really needed, but there are sanity checks for stack pointers:
|
||||||
return TRUE; // caller can remove this operator (we are done, so not really needed, but there are sanity checks for stack pointers)
|
// remove previous operator by overwriting with newest one...
|
||||||
|
PREVIOUS_OPERATOR = NEWEST_OPERATOR;
|
||||||
|
--op_sp; // ...and shrinking operator stack
|
||||||
|
break;
|
||||||
case OPID_SUBEXPR_PAREN:
|
case OPID_SUBEXPR_PAREN:
|
||||||
expression->is_parenthesized = TRUE; // found parentheses. if this is not the outermost level, the outermost level will fix this flag later on.
|
expression->is_parenthesized = TRUE; // found parentheses. if this is not the outermost level, the outermost level will fix this flag later on.
|
||||||
if (GotByte == ')') {
|
if (GotByte == ')') {
|
||||||
// matching parenthesis
|
// matching parenthesis
|
||||||
GetByte(); // eat char
|
GetByte(); // eat ')'
|
||||||
op_sp -= 2; // remove both SUBEXPR_PAREN and TERMINATOR
|
op_sp -= 2; // remove both SUBEXPR_PAREN and TERMINATOR
|
||||||
alu_state = STATE_EXPECT_DYADIC_OP;
|
alu_state = STATE_EXPECT_DYADIC_OP;
|
||||||
return FALSE; // we fixed the stack ourselves, so caller shouldn't touch it
|
} else {
|
||||||
}
|
|
||||||
// unmatched parenthesis, as in "lda ($80,x)"
|
// unmatched parenthesis, as in "lda ($80,x)"
|
||||||
++(expression->open_parentheses); // count
|
++(expression->open_parentheses); // count
|
||||||
return TRUE; // caller can remove "SUBEXPR_PAREN" operator from stack
|
// remove previous operator by overwriting with newest one...
|
||||||
|
PREVIOUS_OPERATOR = NEWEST_OPERATOR;
|
||||||
|
--op_sp; // ...and shrinking operator stack
|
||||||
|
}
|
||||||
|
break;
|
||||||
case OPID_START_LIST:
|
case OPID_START_LIST:
|
||||||
if (GotByte == ',') {
|
if (GotByte == ',') {
|
||||||
GetByte(); // eat ','
|
GetByte(); // eat ','
|
||||||
op_stack[op_sp - 1] = &ops_list_append; // change "end of expression" to "append"
|
NEWEST_OPERATOR = &ops_list_append; // change "end of expression" to "append"
|
||||||
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
|
} else if (GotByte == ']') {
|
||||||
return FALSE; // stack remains, so caller shouldn't touch it
|
|
||||||
}
|
|
||||||
if (GotByte == ']') {
|
|
||||||
GetByte(); // eat ']'
|
GetByte(); // eat ']'
|
||||||
op_sp -= 2; // remove both START_LIST and TERMINATOR
|
op_sp -= 2; // remove both START_LIST and TERMINATOR
|
||||||
alu_state = STATE_EXPECT_DYADIC_OP;
|
alu_state = STATE_EXPECT_DYADIC_OP;
|
||||||
return FALSE; // we fixed the stack ourselves, so caller shouldn't touch it
|
} else {
|
||||||
}
|
// unmatched bracket
|
||||||
Throw_error("Unterminated list.");
|
Throw_error("Unterminated list.");
|
||||||
alu_state = STATE_ERROR;
|
alu_state = STATE_ERROR;
|
||||||
return TRUE; // caller can remove START_LIST operator from stack
|
// remove previous operator by overwriting with newest one...
|
||||||
|
PREVIOUS_OPERATOR = NEWEST_OPERATOR;
|
||||||
|
--op_sp; // ...and shrinking operator stack
|
||||||
|
}
|
||||||
|
break;
|
||||||
case OPID_SUBEXPR_BRACKET:
|
case OPID_SUBEXPR_BRACKET:
|
||||||
if (GotByte == ']') {
|
if (GotByte == ']') {
|
||||||
GetByte(); // eat ']'
|
GetByte(); // eat ']'
|
||||||
op_sp -= 2; // remove both SUBEXPR_BRACKET and TERMINATOR
|
op_sp -= 2; // remove both SUBEXPR_BRACKET and TERMINATOR
|
||||||
alu_state = STATE_EXPECT_DYADIC_OP;
|
alu_state = STATE_EXPECT_DYADIC_OP;
|
||||||
return FALSE; // we fixed the stack ourselves, so caller shouldn't touch it
|
} else {
|
||||||
}
|
// unmatched bracket
|
||||||
Throw_error("Unterminated index spec.");
|
Throw_error("Unterminated index spec.");
|
||||||
alu_state = STATE_ERROR;
|
alu_state = STATE_ERROR;
|
||||||
return TRUE; // caller can remove SUBEXPR_BRACKET operator from stack
|
// remove previous operator by overwriting with newest one...
|
||||||
|
PREVIOUS_OPERATOR = NEWEST_OPERATOR;
|
||||||
|
--op_sp; // ...and shrinking operator stack
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Bug_found("IllegalOperatorId", previous);
|
Bug_found("IllegalOperatorId", previous);
|
||||||
}
|
}
|
||||||
// this is unreachable
|
|
||||||
return FALSE; // stack is done, so caller shouldn't touch it
|
|
||||||
}
|
}
|
||||||
|
// put dyadic operator on stack and try to reduce stacks by performing
|
||||||
|
// high-priority operations: as long as the second-to-last operator
|
||||||
// Try to reduce stacks by performing high-priority operations
|
// has a higher priority than the last one, perform the operation of
|
||||||
// (if the previous operator has a higher priority than the current one, do it)
|
// that second-to-last one and remove it from stack.
|
||||||
static void push_dyadic_and_check(struct expression *expression, struct op *op)
|
static void push_dyadic_and_check(struct expression *expression, struct op *op)
|
||||||
{
|
{
|
||||||
struct op *previous_op;
|
PUSH_OP(op); // put newest operator on stack
|
||||||
struct op *current_op;
|
|
||||||
|
|
||||||
PUSH_OP(op);
|
|
||||||
if (alu_state < STATE_MAX_GO_ON)
|
if (alu_state < STATE_MAX_GO_ON)
|
||||||
alu_state = STATE_TRY_TO_REDUCE_STACKS;
|
|
||||||
while (alu_state == STATE_TRY_TO_REDUCE_STACKS) {
|
|
||||||
if (op_sp < 2) {
|
|
||||||
// we only have one operator, which must be "start of expression",
|
|
||||||
// so there isn't anything left to do, so go on trying to parse the expression
|
|
||||||
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
|
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
|
||||||
|
while (alu_state == STATE_EXPECT_ARG_OR_MONADIC_OP) {
|
||||||
|
// if there is only one operator left on op stack, it must be
|
||||||
|
// "start of expression", so there isn't anything to do here:
|
||||||
|
if (op_sp < 2)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
previous_op = op_stack[op_sp - 2];
|
// if previous operator has lower piority, nothing to do here:
|
||||||
current_op = op_stack[op_sp - 1];
|
if (PREVIOUS_OPERATOR->priority < NEWEST_OPERATOR->priority)
|
||||||
|
|
||||||
// previous operator has lower piority than current one? then do nothing.
|
|
||||||
if (previous_op->priority < current_op->priority) {
|
|
||||||
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// previous operator has same priority as current one? then check associativity
|
// if priorities are the same, check associativity:
|
||||||
if ((previous_op->priority == current_op->priority)
|
if ((PREVIOUS_OPERATOR->priority == NEWEST_OPERATOR->priority)
|
||||||
&& (current_op->priority == PRIO_POWEROF)
|
&& (NEWEST_OPERATOR->priority == PRIO_POWEROF)
|
||||||
&& (config.wanted_version >= VER_RIGHTASSOCIATIVEPOWEROF)) {
|
&& (config.wanted_version >= VER_RIGHTASSOCIATIVEPOWEROF))
|
||||||
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// we now know that either
|
// ok, so now perform operation indicated by previous operator!
|
||||||
// - the previous operator has higher priority, or
|
switch (PREVIOUS_OPERATOR->group) {
|
||||||
// - it has the same priority and is left-associative,
|
case OPGROUP_MONADIC:
|
||||||
// so perform that operation!
|
// stacks: ... ... previous op(monadic) newest arg newest op(dyadic)
|
||||||
#define ARG_PREV (arg_stack[arg_sp - 2])
|
|
||||||
#define ARG_NOW (arg_stack[arg_sp - 1])
|
|
||||||
switch (previous_op->group) {
|
|
||||||
case OPGROUP_MONADIC: // monadic operators
|
|
||||||
if (arg_sp < 1)
|
if (arg_sp < 1)
|
||||||
Bug_found("ArgStackEmpty", arg_sp);
|
Bug_found("ArgStackEmpty", arg_sp);
|
||||||
ARG_NOW.type->monadic_op(&ARG_NOW, previous_op);
|
NEWEST_ARGUMENT.type->monadic_op(&NEWEST_ARGUMENT, PREVIOUS_OPERATOR);
|
||||||
// operation was something other than parentheses
|
expression->is_parenthesized = FALSE; // operation was something other than parentheses
|
||||||
expression->is_parenthesized = FALSE;
|
// now remove previous operator by overwriting with newest one...
|
||||||
|
PREVIOUS_OPERATOR = NEWEST_OPERATOR;
|
||||||
|
--op_sp; // ...and shrinking operator stack
|
||||||
break;
|
break;
|
||||||
case OPGROUP_DYADIC: // dyadic operators
|
case OPGROUP_DYADIC:
|
||||||
|
// stacks: previous arg previous op(dyadic) newest arg newest op(dyadic)
|
||||||
if (arg_sp < 2)
|
if (arg_sp < 2)
|
||||||
Bug_found("NotEnoughArgs", arg_sp);
|
Bug_found("NotEnoughArgs", arg_sp);
|
||||||
ARG_PREV.type->dyadic_op(&ARG_PREV, previous_op, &ARG_NOW);
|
PREVIOUS_ARGUMENT.type->dyadic_op(&PREVIOUS_ARGUMENT, PREVIOUS_OPERATOR, &NEWEST_ARGUMENT);
|
||||||
// decrement argument stack pointer because dyadic operator merged two arguments into one
|
expression->is_parenthesized = FALSE; // operation was something other than parentheses
|
||||||
--arg_sp;
|
// now remove previous operator by overwriting with newest one...
|
||||||
// operation was something other than parentheses
|
PREVIOUS_OPERATOR = NEWEST_OPERATOR;
|
||||||
expression->is_parenthesized = FALSE;
|
--op_sp; // ...and shrinking operator stack
|
||||||
|
--arg_sp; // and then shrink argument stack because two arguments just became one
|
||||||
break;
|
break;
|
||||||
case OPGROUP_SPECIAL: // special (pseudo) operators
|
case OPGROUP_SPECIAL:
|
||||||
if (current_op->id != OPID_TERMINATOR)
|
// stacks: ... ... previous op(special) newest arg newest op(dyadic)
|
||||||
Bug_found("StrangeOperator", current_op->id);
|
if (NEWEST_OPERATOR->id != OPID_TERMINATOR)
|
||||||
if (!handle_special_operator(expression, previous_op->id))
|
Bug_found("StrangeOperator", NEWEST_OPERATOR->id);
|
||||||
continue; // called fn has fixed the stack, so we don't touch it
|
handle_special_operator(expression, PREVIOUS_OPERATOR->id);
|
||||||
|
// the function above fixes both stacks and "is_parenthesized"!
|
||||||
// both monadics and dyadics clear "is_parenthesized", but here we don't touch it!
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Bug_found("IllegalOperatorGroup", previous_op->group);
|
Bug_found("IllegalOperatorGroup", PREVIOUS_OPERATOR->group);
|
||||||
}
|
}
|
||||||
// shared endings for "we did the operation indicated by previous operator":
|
|
||||||
// fix stack:
|
|
||||||
// remove previous operator and shift down current one
|
|
||||||
// CAUTION - fiddling with our local copies like "previous_op = current_op" is not enough... ;)
|
|
||||||
op_stack[op_sp - 2] = op_stack[op_sp - 1];
|
|
||||||
--op_sp; // decrement operator stack pointer
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2403,9 +2391,6 @@ static int parse_expression(struct expression *expression)
|
|||||||
case STATE_EXPECT_DYADIC_OP:
|
case STATE_EXPECT_DYADIC_OP:
|
||||||
expect_dyadic_operator(expression);
|
expect_dyadic_operator(expression);
|
||||||
break;
|
break;
|
||||||
case STATE_TRY_TO_REDUCE_STACKS:
|
|
||||||
Bug_found("TryToReduce", 0); // FIXME - add to docs or remove!
|
|
||||||
break;
|
|
||||||
case STATE_MAX_GO_ON: // suppress
|
case STATE_MAX_GO_ON: // suppress
|
||||||
case STATE_ERROR: // compiler
|
case STATE_ERROR: // compiler
|
||||||
case STATE_END: // warnings
|
case STATE_END: // warnings
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#define RELEASE "0.96.5" // update before release FIXME
|
#define RELEASE "0.96.5" // update before release FIXME
|
||||||
#define CODENAME "Fenchurch" // update before release
|
#define CODENAME "Fenchurch" // update before release
|
||||||
#define CHANGE_DATE "21 June" // update before release FIXME
|
#define CHANGE_DATE "22 June" // update before release FIXME
|
||||||
#define CHANGE_YEAR "2020" // update before release
|
#define CHANGE_YEAR "2020" // update before release
|
||||||
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
||||||
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
||||||
|
@ -139,6 +139,9 @@
|
|||||||
+a int(3 + 4) + .8 = (int(3 + 4) + .8)
|
+a int(3 + 4) + .8 = (int(3 + 4) + .8)
|
||||||
+a int(3 + 4) + .8 != int((3 + 4) + .8)
|
+a int(3 + 4) + .8 != int((3 + 4) + .8)
|
||||||
|
|
||||||
|
+a 3*(4+5)+7 = (3*(4+5))+7
|
||||||
|
+a 3*(4+5)+7 != 3*((4+5)+7)
|
||||||
|
|
||||||
; test dyadics with different arg types
|
; test dyadics with different arg types
|
||||||
; int/int
|
; int/int
|
||||||
+a 3 ^ 2 = 9
|
+a 3 ^ 2 = 9
|
||||||
|
Loading…
Reference in New Issue
Block a user