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:
marcobaye 2020-06-21 22:30:06 +00:00
parent 89344d34ee
commit be72f71faa
3 changed files with 82 additions and 94 deletions

171
src/alu.c
View File

@ -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)"
++(expression->open_parentheses); // count
// remove previous operator by overwriting with newest one...
PREVIOUS_OPERATOR = NEWEST_OPERATOR;
--op_sp; // ...and shrinking operator stack
} }
// unmatched parenthesis, as in "lda ($80,x)" break;
++(expression->open_parentheses); // count
return TRUE; // caller can remove "SUBEXPR_PAREN" operator from stack
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.");
alu_state = STATE_ERROR;
// remove previous operator by overwriting with newest one...
PREVIOUS_OPERATOR = NEWEST_OPERATOR;
--op_sp; // ...and shrinking operator stack
} }
Throw_error("Unterminated list."); break;
alu_state = STATE_ERROR;
return TRUE; // caller can remove START_LIST operator from stack
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.");
alu_state = STATE_ERROR;
// remove previous operator by overwriting with newest one...
PREVIOUS_OPERATOR = NEWEST_OPERATOR;
--op_sp; // ...and shrinking operator stack
} }
Throw_error("Unterminated index spec."); break;
alu_state = STATE_ERROR;
return TRUE; // caller can remove SUBEXPR_BRACKET operator from stack
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; alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
while (alu_state == STATE_TRY_TO_REDUCE_STACKS) { while (alu_state == STATE_EXPECT_ARG_OR_MONADIC_OP) {
if (op_sp < 2) { // if there is only one operator left on op stack, it must be
// we only have one operator, which must be "start of expression", // "start of expression", so there isn't anything to do here:
// so there isn't anything left to do, so go on trying to parse the expression if (op_sp < 2)
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
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

View File

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

View File

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