Data update
This commit is contained in:
parent
5150844a7d
commit
4bb20c9b71
7735 changed files with 38060 additions and 199180 deletions
|
|
@ -3,35 +3,35 @@
|
|||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
const char *s;
|
||||
int len, prec, assoc;
|
||||
const char *s;
|
||||
int len, prec, assoc;
|
||||
} str_tok_t;
|
||||
|
||||
typedef struct {
|
||||
const char * str;
|
||||
int assoc, prec;
|
||||
regex_t re;
|
||||
const char * str;
|
||||
int assoc, prec;
|
||||
regex_t re;
|
||||
} pat_t;
|
||||
|
||||
enum assoc { A_NONE, A_L, A_R };
|
||||
pat_t pat_eos = {"", A_NONE, 0};
|
||||
|
||||
pat_t pat_ops[] = {
|
||||
{"^\\)", A_NONE, -1},
|
||||
{"^\\*\\*", A_R, 3},
|
||||
{"^\\^", A_R, 3},
|
||||
{"^\\*", A_L, 2},
|
||||
{"^/", A_L, 2},
|
||||
{"^\\+", A_L, 1},
|
||||
{"^-", A_L, 1},
|
||||
{0}
|
||||
{"^\\)", A_NONE, -1},
|
||||
{"^\\*\\*", A_R, 3},
|
||||
{"^\\^", A_R, 3},
|
||||
{"^\\*", A_L, 2},
|
||||
{"^/", A_L, 2},
|
||||
{"^\\+", A_L, 1},
|
||||
{"^-", A_L, 1},
|
||||
{0}
|
||||
};
|
||||
|
||||
pat_t pat_arg[] = {
|
||||
{"^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?"},
|
||||
{"^[a-zA-Z_][a-zA-Z_0-9]*"},
|
||||
{"^\\(", A_L, -1},
|
||||
{0}
|
||||
{"^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?"},
|
||||
{"^[a-zA-Z_][a-zA-Z_0-9]*"},
|
||||
{"^\\(", A_L, -1},
|
||||
{0}
|
||||
};
|
||||
|
||||
str_tok_t stack[256]; /* assume these are big enough */
|
||||
|
|
@ -43,16 +43,16 @@ int l_queue, l_stack;
|
|||
|
||||
void display(const char *s)
|
||||
{
|
||||
int i;
|
||||
printf("\033[1;1H\033[JText | %s", s);
|
||||
printf("\nStack| ");
|
||||
for (i = 0; i < l_stack; i++)
|
||||
printf("%.*s ", stack[i].len, stack[i].s); // uses C99 format strings
|
||||
printf("\nQueue| ");
|
||||
for (i = 0; i < l_queue; i++)
|
||||
printf("%.*s ", queue[i].len, queue[i].s);
|
||||
puts("\n\n<press enter>");
|
||||
getchar();
|
||||
int i;
|
||||
printf("\033[1;1H\033[JText | %s", s);
|
||||
printf("\nStack| ");
|
||||
for (i = 0; i < l_stack; i++)
|
||||
printf("%.*s ", stack[i].len, stack[i].s); // uses C99 format strings
|
||||
printf("\nQueue| ");
|
||||
for (i = 0; i < l_queue; i++)
|
||||
printf("%.*s ", queue[i].len, queue[i].s);
|
||||
puts("\n\n<press enter>");
|
||||
getchar();
|
||||
}
|
||||
|
||||
int prec_booster;
|
||||
|
|
@ -61,125 +61,125 @@ int prec_booster;
|
|||
|
||||
int init(void)
|
||||
{
|
||||
int i;
|
||||
pat_t *p;
|
||||
int i;
|
||||
pat_t *p;
|
||||
|
||||
for (i = 0, p = pat_ops; p[i].str; i++)
|
||||
if (regcomp(&(p[i].re), p[i].str, REG_NEWLINE|REG_EXTENDED))
|
||||
fail("comp", p[i].str);
|
||||
for (i = 0, p = pat_ops; p[i].str; i++)
|
||||
if (regcomp(&(p[i].re), p[i].str, REG_NEWLINE|REG_EXTENDED))
|
||||
fail("comp", p[i].str);
|
||||
|
||||
for (i = 0, p = pat_arg; p[i].str; i++)
|
||||
if (regcomp(&(p[i].re), p[i].str, REG_NEWLINE|REG_EXTENDED))
|
||||
fail("comp", p[i].str);
|
||||
for (i = 0, p = pat_arg; p[i].str; i++)
|
||||
if (regcomp(&(p[i].re), p[i].str, REG_NEWLINE|REG_EXTENDED))
|
||||
fail("comp", p[i].str);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
pat_t* match(const char *s, pat_t *p, str_tok_t * t, const char **e)
|
||||
{
|
||||
int i;
|
||||
regmatch_t m;
|
||||
int i;
|
||||
regmatch_t m;
|
||||
|
||||
while (*s == ' ') s++;
|
||||
*e = s;
|
||||
while (*s == ' ') s++;
|
||||
*e = s;
|
||||
|
||||
if (!*s) return &pat_eos;
|
||||
if (!*s) return &pat_eos;
|
||||
|
||||
for (i = 0; p[i].str; i++) {
|
||||
if (regexec(&(p[i].re), s, 1, &m, REG_NOTEOL))
|
||||
continue;
|
||||
t->s = s;
|
||||
*e = s + (t->len = m.rm_eo - m.rm_so);
|
||||
return p + i;
|
||||
}
|
||||
return 0;
|
||||
for (i = 0; p[i].str; i++) {
|
||||
if (regexec(&(p[i].re), s, 1, &m, REG_NOTEOL))
|
||||
continue;
|
||||
t->s = s;
|
||||
*e = s + (t->len = m.rm_eo - m.rm_so);
|
||||
return p + i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse(const char *s) {
|
||||
pat_t *p;
|
||||
str_tok_t *t, tok;
|
||||
pat_t *p;
|
||||
str_tok_t *t, tok;
|
||||
|
||||
prec_booster = l_queue = l_stack = 0;
|
||||
display(s);
|
||||
while (*s) {
|
||||
p = match(s, pat_arg, &tok, &s);
|
||||
if (!p || p == &pat_eos) fail("parse arg", s);
|
||||
prec_booster = l_queue = l_stack = 0;
|
||||
display(s);
|
||||
while (*s) {
|
||||
p = match(s, pat_arg, &tok, &s);
|
||||
if (!p || p == &pat_eos) fail("parse arg", s);
|
||||
|
||||
/* Odd logic here. Don't actually stack the parens: don't need to. */
|
||||
if (p->prec == -1) {
|
||||
prec_booster += 100;
|
||||
continue;
|
||||
}
|
||||
qpush(tok);
|
||||
display(s);
|
||||
/* Odd logic here. Don't actually stack the parens: don't need to. */
|
||||
if (p->prec == -1) {
|
||||
prec_booster += 100;
|
||||
continue;
|
||||
}
|
||||
qpush(tok);
|
||||
display(s);
|
||||
|
||||
re_op: p = match(s, pat_ops, &tok, &s);
|
||||
if (!p) fail("parse op", s);
|
||||
re_op: p = match(s, pat_ops, &tok, &s);
|
||||
if (!p) fail("parse op", s);
|
||||
|
||||
tok.assoc = p->assoc;
|
||||
tok.prec = p->prec;
|
||||
tok.assoc = p->assoc;
|
||||
tok.prec = p->prec;
|
||||
|
||||
if (p->prec > 0)
|
||||
tok.prec = p->prec + prec_booster;
|
||||
else if (p->prec == -1) {
|
||||
if (prec_booster < 100)
|
||||
fail("unmatched )", s);
|
||||
tok.prec = prec_booster;
|
||||
}
|
||||
if (p->prec > 0)
|
||||
tok.prec = p->prec + prec_booster;
|
||||
else if (p->prec == -1) {
|
||||
if (prec_booster < 100)
|
||||
fail("unmatched )", s);
|
||||
tok.prec = prec_booster;
|
||||
}
|
||||
|
||||
while (l_stack) {
|
||||
t = stack + l_stack - 1;
|
||||
if (!(t->prec == tok.prec && t->assoc == A_L)
|
||||
&& t->prec <= tok.prec)
|
||||
break;
|
||||
qpush(spop());
|
||||
display(s);
|
||||
}
|
||||
while (l_stack) {
|
||||
t = stack + l_stack - 1;
|
||||
if (!(t->prec == tok.prec && t->assoc == A_L)
|
||||
&& t->prec <= tok.prec)
|
||||
break;
|
||||
qpush(spop());
|
||||
display(s);
|
||||
}
|
||||
|
||||
if (p->prec == -1) {
|
||||
prec_booster -= 100;
|
||||
goto re_op;
|
||||
}
|
||||
if (p->prec == -1) {
|
||||
prec_booster -= 100;
|
||||
goto re_op;
|
||||
}
|
||||
|
||||
if (!p->prec) {
|
||||
display(s);
|
||||
if (prec_booster)
|
||||
fail("unmatched (", s);
|
||||
return 1;
|
||||
}
|
||||
if (!p->prec) {
|
||||
display(s);
|
||||
if (prec_booster)
|
||||
fail("unmatched (", s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
spush(tok);
|
||||
display(s);
|
||||
}
|
||||
spush(tok);
|
||||
display(s);
|
||||
}
|
||||
|
||||
if (p->prec > 0)
|
||||
fail("unexpected eol", s);
|
||||
if (p->prec > 0)
|
||||
fail("unexpected eol", s);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
const char *tests[] = {
|
||||
"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3", /* RC mandated: OK */
|
||||
"123", /* OK */
|
||||
"3+4 * 2 / ( 1 - 5 ) ^ 2 ^ 3.14", /* OK */
|
||||
"(((((((1+2+3**(4 + 5))))))", /* bad parens */
|
||||
"a^(b + c/d * .1e5)!", /* unknown op */
|
||||
"(1**2)**3", /* OK */
|
||||
"2 + 2 *", /* unexpected eol */
|
||||
0
|
||||
};
|
||||
int i;
|
||||
const char *tests[] = {
|
||||
"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3", /* RC mandated: OK */
|
||||
"123", /* OK */
|
||||
"3+4 * 2 / ( 1 - 5 ) ^ 2 ^ 3.14", /* OK */
|
||||
"(((((((1+2+3**(4 + 5))))))", /* bad parens */
|
||||
"a^(b + c/d * .1e5)!", /* unknown op */
|
||||
"(1**2)**3", /* OK */
|
||||
"2 + 2 *", /* unexpected eol */
|
||||
0
|
||||
};
|
||||
|
||||
if (!init()) return 1;
|
||||
for (i = 0; tests[i]; i++) {
|
||||
printf("Testing string `%s' <enter>\n", tests[i]);
|
||||
getchar();
|
||||
if (!init()) return 1;
|
||||
for (i = 0; tests[i]; i++) {
|
||||
printf("Testing string `%s' <enter>\n", tests[i]);
|
||||
getchar();
|
||||
|
||||
printf("string `%s': %s\n\n", tests[i],
|
||||
parse(tests[i]) ? "Ok" : "Error");
|
||||
}
|
||||
printf("string `%s': %s\n\n", tests[i],
|
||||
parse(tests[i]) ? "Ok" : "Error");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,106 +1,106 @@
|
|||
import ceylon.collection {
|
||||
|
||||
ArrayList
|
||||
ArrayList
|
||||
}
|
||||
|
||||
abstract class Token(String|Integer data) of IntegerLiteral | Operator | leftParen | rightParen {
|
||||
string => data.string;
|
||||
string => data.string;
|
||||
}
|
||||
class IntegerLiteral(shared Integer integer) extends Token(integer) {}
|
||||
class Operator extends Token {
|
||||
|
||||
shared Integer precedence;
|
||||
shared Boolean rightAssoc;
|
||||
|
||||
shared new plus extends Token("+") {
|
||||
precedence = 2;
|
||||
rightAssoc = false;
|
||||
}
|
||||
shared new minus extends Token("-") {
|
||||
precedence = 2;
|
||||
rightAssoc = false;
|
||||
}
|
||||
shared new times extends Token("*") {
|
||||
precedence = 3;
|
||||
rightAssoc = false;
|
||||
}
|
||||
shared new divides extends Token("/") {
|
||||
precedence = 3;
|
||||
rightAssoc = false;
|
||||
}
|
||||
shared new power extends Token("^") {
|
||||
precedence = 4;
|
||||
rightAssoc = true;
|
||||
}
|
||||
shared Integer precedence;
|
||||
shared Boolean rightAssoc;
|
||||
|
||||
shared Boolean below(Operator other) =>
|
||||
!rightAssoc && precedence <= other.precedence || rightAssoc && precedence < other.precedence;
|
||||
shared new plus extends Token("+") {
|
||||
precedence = 2;
|
||||
rightAssoc = false;
|
||||
}
|
||||
shared new minus extends Token("-") {
|
||||
precedence = 2;
|
||||
rightAssoc = false;
|
||||
}
|
||||
shared new times extends Token("*") {
|
||||
precedence = 3;
|
||||
rightAssoc = false;
|
||||
}
|
||||
shared new divides extends Token("/") {
|
||||
precedence = 3;
|
||||
rightAssoc = false;
|
||||
}
|
||||
shared new power extends Token("^") {
|
||||
precedence = 4;
|
||||
rightAssoc = true;
|
||||
}
|
||||
|
||||
shared Boolean below(Operator other) =>
|
||||
!rightAssoc && precedence <= other.precedence || rightAssoc && precedence < other.precedence;
|
||||
}
|
||||
object leftParen extends Token("(") {}
|
||||
object rightParen extends Token(")") {}
|
||||
|
||||
|
||||
shared void run() {
|
||||
|
||||
function shunt(String input) {
|
||||
|
||||
function tokenize(String input) =>
|
||||
input.split().map((String element) =>
|
||||
switch(element.trimmed)
|
||||
case("(") leftParen
|
||||
case(")") rightParen
|
||||
case("+") Operator.plus
|
||||
case("-") Operator.minus
|
||||
case("*") Operator.times
|
||||
case("/") Operator.divides
|
||||
case("^") Operator.power
|
||||
else IntegerLiteral(parseInteger(element) else 0)); // no error handling
|
||||
|
||||
value outputQueue = ArrayList<Token>();
|
||||
value operatorStack = ArrayList<Token>();
|
||||
|
||||
void report(String action) {
|
||||
print("``action.padTrailing(22)`` | ``" ".join(outputQueue).padTrailing(25)`` | ``" ".join(operatorStack).padTrailing(10)``");
|
||||
}
|
||||
|
||||
print("input is ``input``\n");
|
||||
print("Action | Output Queue | Operators' Stack
|
||||
-----------------------|---------------------------|-----------------");
|
||||
|
||||
for(token in tokenize(input)) {
|
||||
switch(token)
|
||||
case(is IntegerLiteral) {
|
||||
outputQueue.offer(token);
|
||||
report("``token`` from input to queue");
|
||||
}
|
||||
case(leftParen) {
|
||||
operatorStack.push(token);
|
||||
report("``token`` from input to stack");
|
||||
}
|
||||
case(rightParen){
|
||||
while(exists top = operatorStack.pop(), top != leftParen) {
|
||||
outputQueue.offer(top);
|
||||
report("``top`` from stack to queue");
|
||||
}
|
||||
}
|
||||
case(is Operator) {
|
||||
while(exists top = operatorStack.top, is Operator top, token.below(top)) {
|
||||
operatorStack.pop();
|
||||
outputQueue.offer(top);
|
||||
report("``top`` from stack to queue");
|
||||
}
|
||||
operatorStack.push(token);
|
||||
report("``token`` from input to stack");
|
||||
}
|
||||
}
|
||||
while(exists top = operatorStack.pop()) {
|
||||
outputQueue.offer(top);
|
||||
report("``top`` from stack to queue");
|
||||
}
|
||||
return " ".join(outputQueue);
|
||||
}
|
||||
|
||||
value rpn = shunt("3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3");
|
||||
assert(rpn == "3 4 2 * 1 5 - 2 3 ^ ^ / +");
|
||||
print("\nthe result is ``rpn``");
|
||||
|
||||
function shunt(String input) {
|
||||
|
||||
function tokenize(String input) =>
|
||||
input.split().map((String element) =>
|
||||
switch(element.trimmed)
|
||||
case("(") leftParen
|
||||
case(")") rightParen
|
||||
case("+") Operator.plus
|
||||
case("-") Operator.minus
|
||||
case("*") Operator.times
|
||||
case("/") Operator.divides
|
||||
case("^") Operator.power
|
||||
else IntegerLiteral(parseInteger(element) else 0)); // no error handling
|
||||
|
||||
value outputQueue = ArrayList<Token>();
|
||||
value operatorStack = ArrayList<Token>();
|
||||
|
||||
void report(String action) {
|
||||
print("``action.padTrailing(22)`` | ``" ".join(outputQueue).padTrailing(25)`` | ``" ".join(operatorStack).padTrailing(10)``");
|
||||
}
|
||||
|
||||
print("input is ``input``\n");
|
||||
print("Action | Output Queue | Operators' Stack
|
||||
-----------------------|---------------------------|-----------------");
|
||||
|
||||
for(token in tokenize(input)) {
|
||||
switch(token)
|
||||
case(is IntegerLiteral) {
|
||||
outputQueue.offer(token);
|
||||
report("``token`` from input to queue");
|
||||
}
|
||||
case(leftParen) {
|
||||
operatorStack.push(token);
|
||||
report("``token`` from input to stack");
|
||||
}
|
||||
case(rightParen){
|
||||
while(exists top = operatorStack.pop(), top != leftParen) {
|
||||
outputQueue.offer(top);
|
||||
report("``top`` from stack to queue");
|
||||
}
|
||||
}
|
||||
case(is Operator) {
|
||||
while(exists top = operatorStack.top, is Operator top, token.below(top)) {
|
||||
operatorStack.pop();
|
||||
outputQueue.offer(top);
|
||||
report("``top`` from stack to queue");
|
||||
}
|
||||
operatorStack.push(token);
|
||||
report("``token`` from input to stack");
|
||||
}
|
||||
}
|
||||
while(exists top = operatorStack.pop()) {
|
||||
outputQueue.offer(top);
|
||||
report("``top`` from stack to queue");
|
||||
}
|
||||
return " ".join(outputQueue);
|
||||
}
|
||||
|
||||
value rpn = shunt("3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3");
|
||||
assert(rpn == "3 4 2 * 1 5 - 2 3 ^ ^ / +");
|
||||
print("\nthe result is ``rpn``");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
MODULE COMPILER !At least of arithmetic expressions.
|
||||
INTEGER KBD,MSG !I/O units.
|
||||
MODULE COMPILER !At least of arithmetic expressions.
|
||||
INTEGER KBD,MSG !I/O units.
|
||||
|
||||
INTEGER ENUFF !How long s a piece of string?
|
||||
PARAMETER (ENUFF = 66) !This long.
|
||||
CHARACTER*(ENUFF) RP !Holds the Reverse Polish Notation.
|
||||
INTEGER LR !And this is its length.
|
||||
INTEGER ENUFF !How long s a piece of string?
|
||||
PARAMETER (ENUFF = 66) !This long.
|
||||
CHARACTER*(ENUFF) RP !Holds the Reverse Polish Notation.
|
||||
INTEGER LR !And this is its length.
|
||||
|
||||
INTEGER OPSYMBOLS !Recognised operator symbols.
|
||||
PARAMETER (OPSYMBOLS = 11) !There are also some associates.
|
||||
TYPE SYMB !To recognise symbols and carry associated information.
|
||||
CHARACTER*1 IS !Its text. Careful with the trailing space and comparisons.
|
||||
INTEGER*1 PRECEDENCE !Controls the order of evaluation.
|
||||
CHARACTER*48 USAGE !Description.
|
||||
END TYPE SYMB !The cross-linkage of precedences is tricky.
|
||||
TYPE(SYMB) SYMBOL(0:OPSYMBOLS) !Righto, I'll have some.
|
||||
PARAMETER (SYMBOL =(/ !Note that "*" is not to be seen as a match to "**".
|
||||
INTEGER OPSYMBOLS !Recognised operator symbols.
|
||||
PARAMETER (OPSYMBOLS = 11) !There are also some associates.
|
||||
TYPE SYMB !To recognise symbols and carry associated information.
|
||||
CHARACTER*1 IS !Its text. Careful with the trailing space and comparisons.
|
||||
INTEGER*1 PRECEDENCE !Controls the order of evaluation.
|
||||
CHARACTER*48 USAGE !Description.
|
||||
END TYPE SYMB !The cross-linkage of precedences is tricky.
|
||||
TYPE(SYMB) SYMBOL(0:OPSYMBOLS) !Righto, I'll have some.
|
||||
PARAMETER (SYMBOL =(/ !Note that "*" is not to be seen as a match to "**".
|
||||
o SYMB(" ", 0,"Not recognised as an operator's symbol."),
|
||||
1 SYMB(" ", 1,"separates symbols and aids legibility."),
|
||||
2 SYMB(")", 4,"opened with ( to bracket a sub-expression."),
|
||||
|
|
@ -28,190 +28,190 @@
|
|||
o SYMB("÷",12,"division for those with a fancy keyboard."),
|
||||
C 13 is used so that stacked ^ will have lower priority than incoming ^, thus delivering right-to-left evaluation.
|
||||
1 SYMB("^",14,"raise to power. Not recognised is **.")/))
|
||||
CHARACTER*3 BRAOPEN,BRACLOSE !Three types are allowed.
|
||||
PARAMETER (BRAOPEN = "([{", BRACLOSE = ")]}") !These.
|
||||
INTEGER BRALEVEL !In and out, in and out. That's the game.
|
||||
INTEGER PRBRA,PRPOW !Special double values.
|
||||
PARAMETER (PRBRA = SYMBOL( 3).PRECEDENCE) !Bracketing
|
||||
PARAMETER (PRPOW = SYMBOL(11).PRECEDENCE) !And powers refer leftwards.
|
||||
CHARACTER*3 BRAOPEN,BRACLOSE !Three types are allowed.
|
||||
PARAMETER (BRAOPEN = "([{", BRACLOSE = ")]}") !These.
|
||||
INTEGER BRALEVEL !In and out, in and out. That's the game.
|
||||
INTEGER PRBRA,PRPOW !Special double values.
|
||||
PARAMETER (PRBRA = SYMBOL( 3).PRECEDENCE) !Bracketing
|
||||
PARAMETER (PRPOW = SYMBOL(11).PRECEDENCE) !And powers refer leftwards.
|
||||
|
||||
CHARACTER*10 DIGIT !Numberish is a bit more complex.
|
||||
PARAMETER (DIGIT = "0123456789") !But this will do for integers.
|
||||
CHARACTER*10 DIGIT !Numberish is a bit more complex.
|
||||
PARAMETER (DIGIT = "0123456789") !But this will do for integers.
|
||||
|
||||
INTEGER STACKLIMIT !How high is a stack?
|
||||
PARAMETER (STACKLIMIT = 66) !This should suffice.
|
||||
TYPE DEFERRED !I need a siding for lower-precedence operations.
|
||||
CHARACTER*1 OPC !The operation code.
|
||||
INTEGER*1 PRECEDENCE !Its precedence in the siding may differ.
|
||||
END TYPE DEFERRED !Anyway, that's enough.
|
||||
TYPE(DEFERRED) OPSTACK(0:STACKLIMIT) !One siding, please.
|
||||
INTEGER OSP !The operation stack pointer.
|
||||
INTEGER STACKLIMIT !How high is a stack?
|
||||
PARAMETER (STACKLIMIT = 66) !This should suffice.
|
||||
TYPE DEFERRED !I need a siding for lower-precedence operations.
|
||||
CHARACTER*1 OPC !The operation code.
|
||||
INTEGER*1 PRECEDENCE !Its precedence in the siding may differ.
|
||||
END TYPE DEFERRED !Anyway, that's enough.
|
||||
TYPE(DEFERRED) OPSTACK(0:STACKLIMIT) !One siding, please.
|
||||
INTEGER OSP !The operation stack pointer.
|
||||
|
||||
INTEGER INCOMING,TOKENTYPE,NOTHING,ANUMBER,OPENBRA,HUH !Some mnemonics.
|
||||
PARAMETER (NOTHING = 0, ANUMBER = -1, OPENBRA = -2, HUH = -3) !The ordering is not arbitrary.
|
||||
CONTAINS !Now to mess about.
|
||||
SUBROUTINE EMIT(STUFF) !The objective is to produce some RPN text.
|
||||
CHARACTER*(*) STUFF !The term of the moment.
|
||||
INTEGER L !A length.
|
||||
WRITE (MSG,1) STUFF !Announce.
|
||||
1 FORMAT ("Emit ",A) !Whatever it is.
|
||||
IF (STUFF.EQ."") RETURN !Ha ha.
|
||||
L = LEN(STUFF) !So, how much is there to append?
|
||||
IF (LR + L.GE.ENUFF) STOP "Too much RPN for RP!" !Perhaps too much.
|
||||
IF (LR.GT.0) THEN !Is there existing stuff?
|
||||
LR = LR + 1 !Yes. Advance one,
|
||||
RP(LR:LR) = " " !And place a space.
|
||||
END IF !So much for separators.
|
||||
RP(LR + 1:LR + L) = STUFF !Place the stuff.
|
||||
LR = LR + L !Count it in.
|
||||
END SUBROUTINE EMIT !Simple enough, if a bit finicky.
|
||||
INTEGER INCOMING,TOKENTYPE,NOTHING,ANUMBER,OPENBRA,HUH !Some mnemonics.
|
||||
PARAMETER (NOTHING = 0, ANUMBER = -1, OPENBRA = -2, HUH = -3) !The ordering is not arbitrary.
|
||||
CONTAINS !Now to mess about.
|
||||
SUBROUTINE EMIT(STUFF) !The objective is to produce some RPN text.
|
||||
CHARACTER*(*) STUFF !The term of the moment.
|
||||
INTEGER L !A length.
|
||||
WRITE (MSG,1) STUFF !Announce.
|
||||
1 FORMAT ("Emit ",A) !Whatever it is.
|
||||
IF (STUFF.EQ."") RETURN !Ha ha.
|
||||
L = LEN(STUFF) !So, how much is there to append?
|
||||
IF (LR + L.GE.ENUFF) STOP "Too much RPN for RP!" !Perhaps too much.
|
||||
IF (LR.GT.0) THEN !Is there existing stuff?
|
||||
LR = LR + 1 !Yes. Advance one,
|
||||
RP(LR:LR) = " " !And place a space.
|
||||
END IF !So much for separators.
|
||||
RP(LR + 1:LR + L) = STUFF !Place the stuff.
|
||||
LR = LR + L !Count it in.
|
||||
END SUBROUTINE EMIT !Simple enough, if a bit finicky.
|
||||
|
||||
SUBROUTINE STACKOP(C,P) !Push an item into the siding.
|
||||
CHARACTER*1 C !The operation code.
|
||||
INTEGER P !Its precedence.
|
||||
OSP = OSP + 1 !Stacking up...
|
||||
IF (OSP.GT.STACKLIMIT) STOP "OSP overtopped!" !Perhaps not.
|
||||
OPSTACK(OSP).OPC = C !Righto,
|
||||
OPSTACK(OSP).PRECEDENCE = P !The deed is simple.
|
||||
WRITE (MSG,1) C,OPSTACK(1:OSP) !Announce.
|
||||
SUBROUTINE STACKOP(C,P) !Push an item into the siding.
|
||||
CHARACTER*1 C !The operation code.
|
||||
INTEGER P !Its precedence.
|
||||
OSP = OSP + 1 !Stacking up...
|
||||
IF (OSP.GT.STACKLIMIT) STOP "OSP overtopped!" !Perhaps not.
|
||||
OPSTACK(OSP).OPC = C !Righto,
|
||||
OPSTACK(OSP).PRECEDENCE = P !The deed is simple.
|
||||
WRITE (MSG,1) C,OPSTACK(1:OSP) !Announce.
|
||||
1 FORMAT ("Stack ",A1,9X,",OpStk=",33(A1,I2:","))
|
||||
END SUBROUTINE STACKOP !So this is more for mnemonic ease.
|
||||
END SUBROUTINE STACKOP !So this is more for mnemonic ease.
|
||||
|
||||
LOGICAL FUNCTION COMPILE(TEXT) !A compiler confronts a compiler!
|
||||
CHARACTER*(*) TEXT !To be inspected.
|
||||
INTEGER L1,L2 !Fingers for the scan.
|
||||
CHARACTER*1 C !Character of the moment.
|
||||
INTEGER HAPPY !Ah, shades of mood.
|
||||
LR = 0 !No output yet.
|
||||
OSP = 0 !Nothing stacked.
|
||||
OPSTACK(0).OPC = "" !Prepare a bouncer.
|
||||
OPSTACK(0).PRECEDENCE = 0 !So that loops won't go past.
|
||||
BRALEVEL = 0 !None seen.
|
||||
HAPPY = +1 !Nor any problems.
|
||||
L2 = 1 !Syncopation: one past the end of the previous token.
|
||||
LOGICAL FUNCTION COMPILE(TEXT) !A compiler confronts a compiler!
|
||||
CHARACTER*(*) TEXT !To be inspected.
|
||||
INTEGER L1,L2 !Fingers for the scan.
|
||||
CHARACTER*1 C !Character of the moment.
|
||||
INTEGER HAPPY !Ah, shades of mood.
|
||||
LR = 0 !No output yet.
|
||||
OSP = 0 !Nothing stacked.
|
||||
OPSTACK(0).OPC = "" !Prepare a bouncer.
|
||||
OPSTACK(0).PRECEDENCE = 0 !So that loops won't go past.
|
||||
BRALEVEL = 0 !None seen.
|
||||
HAPPY = +1 !Nor any problems.
|
||||
L2 = 1 !Syncopation: one past the end of the previous token.
|
||||
Chew into an operand, possibly obstructed by an open bracket.
|
||||
100 CALL FORASIGN !Find something to inspect.
|
||||
IF (TOKENTYPE.EQ.NOTHING) THEN !Run off the end?
|
||||
IF (OSP.GT.0) CALL GRUMP("Another operand or one of " !E.g. "1 +".
|
||||
1 //BRAOPEN//" is expected.") !Give a hint, because stacked stuff awaits.
|
||||
ELSE IF (TOKENTYPE.EQ.ANUMBER) THEN !If a number,
|
||||
CALL EMIT(TEXT(L1:L2 - 1)) !Roll all its digits.
|
||||
ELSE IF (TOKENTYPE.EQ.OPENBRA) THEN !Starting a sub-expression?
|
||||
CALL STACKOP(C,PRBRA - 1) !Thus ( has less precedence than ).
|
||||
GO TO 100 !And I still want an operand.
|
||||
C ELSE IF (TOKENTYPE.EQ.ANAME) THEN !Name of something?
|
||||
C CALL EMIT(TEXT(L1:L2 - 1)) !Roll it.
|
||||
ELSE !No further options.
|
||||
CALL GRUMP("Huh? Unexpected "//C) !Probably something like "1 + +"
|
||||
END IF !Righto, finished with operands.
|
||||
100 CALL FORASIGN !Find something to inspect.
|
||||
IF (TOKENTYPE.EQ.NOTHING) THEN !Run off the end?
|
||||
IF (OSP.GT.0) CALL GRUMP("Another operand or one of " !E.g. "1 +".
|
||||
1 //BRAOPEN//" is expected.") !Give a hint, because stacked stuff awaits.
|
||||
ELSE IF (TOKENTYPE.EQ.ANUMBER) THEN !If a number,
|
||||
CALL EMIT(TEXT(L1:L2 - 1)) !Roll all its digits.
|
||||
ELSE IF (TOKENTYPE.EQ.OPENBRA) THEN !Starting a sub-expression?
|
||||
CALL STACKOP(C,PRBRA - 1) !Thus ( has less precedence than ).
|
||||
GO TO 100 !And I still want an operand.
|
||||
C ELSE IF (TOKENTYPE.EQ.ANAME) THEN !Name of something?
|
||||
C CALL EMIT(TEXT(L1:L2 - 1)) !Roll it.
|
||||
ELSE !No further options.
|
||||
CALL GRUMP("Huh? Unexpected "//C) !Probably something like "1 + +"
|
||||
END IF !Righto, finished with operands.
|
||||
Chase after an operator, possibly interrupted by a close bracket,.
|
||||
200 CALL FORASIGN !Find something to inspect.
|
||||
IF (TOKENTYPE.LT.0) THEN !But, have I an operand-like token instead?
|
||||
CALL GRUMP("Operator expected, not "//C) !It seems so.
|
||||
ELSE !Normally, an operator is to hand. Possibly a NOTHING, though.
|
||||
WRITE (MSG,201) C,INCOMING,OPSTACK(1:OSP) !Document it.
|
||||
201 FORMAT ("Oprn=>",A1,"< Prec=",I2, !Try to align with other output.
|
||||
1 ",OpStk=",33(A1,I2:",")) !So as not to clutter the display.
|
||||
DO WHILE(OPSTACK(OSP).PRECEDENCE .GE. INCOMING) !Shunt higher-precedence stuff out.
|
||||
IF (OPSTACK(OSP).PRECEDENCE .EQ. PRBRA - 1) !Only opening brackets have this precedence.
|
||||
1 CALL GRUMP("Unbalanced "//OPSTACK(OSP).OPC) !And they vanish only when meeting their closing bracket.
|
||||
CALL EMIT(OPSTACK(OSP).OPC) !Otherwise we have an operator.
|
||||
OSP = OSP - 1 !It has gone forth.
|
||||
END DO !On to the next.
|
||||
IF (TOKENTYPE.GT.NOTHING) THEN !Now, only lower-precedence items are still in the stack.
|
||||
IF (INCOMING.EQ.PRBRA) THEN !And this is a special arrival.
|
||||
CALL BALANCEBRA(C) !It should match an earlier entry.
|
||||
BRALEVEL = BRALEVEL - 1 !Count it out.
|
||||
GO TO 200 !And I still haven't got an operator.
|
||||
ELSE !All others are normal operators.
|
||||
IF (C.EQ."^") INCOMING = PRPOW - 1 !Special trick to cause leftwards association of x^2^3.
|
||||
CALL STACKOP(C,INCOMING) !Shunt aside, to await the next arrival.
|
||||
END IF !So much for that operator.
|
||||
END IF !Providing it was not just an end-of-input flusher.
|
||||
END IF !And not a misplaced operand.
|
||||
200 CALL FORASIGN !Find something to inspect.
|
||||
IF (TOKENTYPE.LT.0) THEN !But, have I an operand-like token instead?
|
||||
CALL GRUMP("Operator expected, not "//C) !It seems so.
|
||||
ELSE !Normally, an operator is to hand. Possibly a NOTHING, though.
|
||||
WRITE (MSG,201) C,INCOMING,OPSTACK(1:OSP) !Document it.
|
||||
201 FORMAT ("Oprn=>",A1,"< Prec=",I2, !Try to align with other output.
|
||||
1 ",OpStk=",33(A1,I2:",")) !So as not to clutter the display.
|
||||
DO WHILE(OPSTACK(OSP).PRECEDENCE .GE. INCOMING) !Shunt higher-precedence stuff out.
|
||||
IF (OPSTACK(OSP).PRECEDENCE .EQ. PRBRA - 1) !Only opening brackets have this precedence.
|
||||
1 CALL GRUMP("Unbalanced "//OPSTACK(OSP).OPC) !And they vanish only when meeting their closing bracket.
|
||||
CALL EMIT(OPSTACK(OSP).OPC) !Otherwise we have an operator.
|
||||
OSP = OSP - 1 !It has gone forth.
|
||||
END DO !On to the next.
|
||||
IF (TOKENTYPE.GT.NOTHING) THEN !Now, only lower-precedence items are still in the stack.
|
||||
IF (INCOMING.EQ.PRBRA) THEN !And this is a special arrival.
|
||||
CALL BALANCEBRA(C) !It should match an earlier entry.
|
||||
BRALEVEL = BRALEVEL - 1 !Count it out.
|
||||
GO TO 200 !And I still haven't got an operator.
|
||||
ELSE !All others are normal operators.
|
||||
IF (C.EQ."^") INCOMING = PRPOW - 1 !Special trick to cause leftwards association of x^2^3.
|
||||
CALL STACKOP(C,INCOMING) !Shunt aside, to await the next arrival.
|
||||
END IF !So much for that operator.
|
||||
END IF !Providing it was not just an end-of-input flusher.
|
||||
END IF !And not a misplaced operand.
|
||||
Carry on?
|
||||
IF (HAPPY .GT. 0) GO TO 100 !No problems, and not a nothing from the end of the text.
|
||||
IF (HAPPY .GT. 0) GO TO 100 !No problems, and not a nothing from the end of the text.
|
||||
Completed.
|
||||
COMPILE = HAPPY.GE.0 !One hopes so.
|
||||
CONTAINS !Now for some assistants.
|
||||
SUBROUTINE GRUMP(GROWL) !There might be a problem.
|
||||
CHARACTER*(*) GROWL !The fault.
|
||||
WRITE (MSG,1) GROWL !Say it.
|
||||
IF (L1.GT. 1) WRITE (MSG,1) "Tasty:",TEXT( 1:L1 - 1) !Now explain the context.
|
||||
IF (L2.GT.L1) WRITE (MSG,1) "Nasty:",TEXT(L1:L2 - 1) !This is the token when trouble was found.
|
||||
IF (L2.LE.LEN(TEXT)) WRITE (MSG,1) "Misty:",TEXT(L2:) !And this remains to be seen.
|
||||
1 FORMAT (4X,A,1X,A) !A simple layout works nicely for reasonable-length texts.
|
||||
HAPPY = -1 . !Just so.
|
||||
END SUBROUTINE GRUMP !Enuogh said.
|
||||
COMPILE = HAPPY.GE.0 !One hopes so.
|
||||
CONTAINS !Now for some assistants.
|
||||
SUBROUTINE GRUMP(GROWL) !There might be a problem.
|
||||
CHARACTER*(*) GROWL !The fault.
|
||||
WRITE (MSG,1) GROWL !Say it.
|
||||
IF (L1.GT. 1) WRITE (MSG,1) "Tasty:",TEXT( 1:L1 - 1) !Now explain the context.
|
||||
IF (L2.GT.L1) WRITE (MSG,1) "Nasty:",TEXT(L1:L2 - 1) !This is the token when trouble was found.
|
||||
IF (L2.LE.LEN(TEXT)) WRITE (MSG,1) "Misty:",TEXT(L2:) !And this remains to be seen.
|
||||
1 FORMAT (4X,A,1X,A) !A simple layout works nicely for reasonable-length texts.
|
||||
HAPPY = -1 . !Just so.
|
||||
END SUBROUTINE GRUMP !Enuogh said.
|
||||
|
||||
SUBROUTINE BALANCEBRA(B) !Perhaps a happy meeting.
|
||||
CHARACTER*1 B !The closer.
|
||||
CHARACTER*1 O !The putative opener.
|
||||
INTEGER IT,L !Fingers.
|
||||
CHARACTER*88 GROWL !A scratchpad.
|
||||
O = OPSTACK(OSP).OPC !This should match B.
|
||||
WRITE (MSG,1) O,B !Perhaps.
|
||||
1 FORMAT ("Match ",2A) !Show what I've got, anyway.
|
||||
IT = INDEX(BRAOPEN,O) !So, what sort did I save?
|
||||
IF (IT .EQ. INDEX(BRACLOSE,B)) THEN !A friend?
|
||||
OSP = OSP - 1 !Yes. They vanish together.
|
||||
ELSE !Otherwise, something is out of place.
|
||||
GROWL = "Unbalanced {[(...)]} bracketing! The closing " !Alas.
|
||||
1 //B//" is unmatched." !So, a mess.
|
||||
IF (IT.GT.0) GROWL(62:) = "A "//BRACLOSE(IT:IT) !Perhaps there had been no opening bracket.
|
||||
1 //" would be better." !But if there had, this would be its friend.
|
||||
CALL GRUMP(GROWL) !Take that!
|
||||
END IF !So much for discrepancies.
|
||||
END SUBROUTINE BALANCEBRA !But, hopefully, amity prevails.
|
||||
SUBROUTINE BALANCEBRA(B) !Perhaps a happy meeting.
|
||||
CHARACTER*1 B !The closer.
|
||||
CHARACTER*1 O !The putative opener.
|
||||
INTEGER IT,L !Fingers.
|
||||
CHARACTER*88 GROWL !A scratchpad.
|
||||
O = OPSTACK(OSP).OPC !This should match B.
|
||||
WRITE (MSG,1) O,B !Perhaps.
|
||||
1 FORMAT ("Match ",2A) !Show what I've got, anyway.
|
||||
IT = INDEX(BRAOPEN,O) !So, what sort did I save?
|
||||
IF (IT .EQ. INDEX(BRACLOSE,B)) THEN !A friend?
|
||||
OSP = OSP - 1 !Yes. They vanish together.
|
||||
ELSE !Otherwise, something is out of place.
|
||||
GROWL = "Unbalanced {[(...)]} bracketing! The closing " !Alas.
|
||||
1 //B//" is unmatched." !So, a mess.
|
||||
IF (IT.GT.0) GROWL(62:) = "A "//BRACLOSE(IT:IT) !Perhaps there had been no opening bracket.
|
||||
1 //" would be better." !But if there had, this would be its friend.
|
||||
CALL GRUMP(GROWL) !Take that!
|
||||
END IF !So much for discrepancies.
|
||||
END SUBROUTINE BALANCEBRA !But, hopefully, amity prevails.
|
||||
|
||||
SUBROUTINE FORASIGN !See what comes next.
|
||||
INTEGER I !A stepper.
|
||||
L1 = L2 !Pick up where the previous scan left off.
|
||||
10 IF (L1.GT.LEN(TEXT)) THEN !Are we off the end yet?
|
||||
C = "" !Yes. Scrub the marker.
|
||||
L2 = L1 !TEXT(L1:L2 - 1) will be null.
|
||||
TOKENTYPE = NOTHING !But this is to be checked first.
|
||||
INCOMING = SYMBOL(1).PRECEDENCE !For flushing sidetracked operators.
|
||||
HAPPY = 0 !Fading away.
|
||||
ELSE !Otherwise, there is grist.
|
||||
SUBROUTINE FORASIGN !See what comes next.
|
||||
INTEGER I !A stepper.
|
||||
L1 = L2 !Pick up where the previous scan left off.
|
||||
10 IF (L1.GT.LEN(TEXT)) THEN !Are we off the end yet?
|
||||
C = "" !Yes. Scrub the marker.
|
||||
L2 = L1 !TEXT(L1:L2 - 1) will be null.
|
||||
TOKENTYPE = NOTHING !But this is to be checked first.
|
||||
INCOMING = SYMBOL(1).PRECEDENCE !For flushing sidetracked operators.
|
||||
HAPPY = 0 !Fading away.
|
||||
ELSE !Otherwise, there is grist.
|
||||
Check for spaces and move past them.
|
||||
C = TEXT(L1:L1) !Grab the first character of the prospective token.
|
||||
IF (C.LE." ") THEN !Boring?
|
||||
L1 = L1 + 1 !Yes. Step past it.
|
||||
GO TO 10 !And look afresh.
|
||||
END IF !Otherwise, L1 now fingers the start.
|
||||
C = TEXT(L1:L1) !Grab the first character of the prospective token.
|
||||
IF (C.LE." ") THEN !Boring?
|
||||
L1 = L1 + 1 !Yes. Step past it.
|
||||
GO TO 10 !And look afresh.
|
||||
END IF !Otherwise, L1 now fingers the start.
|
||||
Caught something to inspect.
|
||||
L2 = L1 + 1 !This is one beyond. Just for digit strings.
|
||||
IF (INDEX(DIGIT,C).GT.0) THEN !So, has one started?
|
||||
TOKENTYPE = ANUMBER !Yep.
|
||||
20 IF (L2.LE.LEN(TEXT)) THEN !Probe ahead.
|
||||
IF (INDEX(DIGIT,TEXT(L2:L2)).GT.0) THEN !Another digit?
|
||||
L2 = L2 + 1 !Yes. Leaving L1 fingering its start,
|
||||
GO TO 20 !Chase its end.
|
||||
END IF !So much for another digit.
|
||||
END IF !And checking against the end.
|
||||
C ELSE IF (INDEX(LETTERS,C).GT.0) THEN !Some sort of name?
|
||||
L2 = L1 + 1 !This is one beyond. Just for digit strings.
|
||||
IF (INDEX(DIGIT,C).GT.0) THEN !So, has one started?
|
||||
TOKENTYPE = ANUMBER !Yep.
|
||||
20 IF (L2.LE.LEN(TEXT)) THEN !Probe ahead.
|
||||
IF (INDEX(DIGIT,TEXT(L2:L2)).GT.0) THEN !Another digit?
|
||||
L2 = L2 + 1 !Yes. Leaving L1 fingering its start,
|
||||
GO TO 20 !Chase its end.
|
||||
END IF !So much for another digit.
|
||||
END IF !And checking against the end.
|
||||
C ELSE IF (INDEX(LETTERS,C).GT.0) THEN !Some sort of name?
|
||||
C advance L2 while in NAMEISH.
|
||||
ELSE IF (INDEX(BRAOPEN,C).GT.0) THEN !An open bracket?
|
||||
TOKENTYPE = OPENBRA !Yep.
|
||||
ELSE !Otherwise, anything else.
|
||||
DO I = OPSYMBOLS,1,-1 !Scan backwards, to find ** before *, if present.
|
||||
IF (SYMBOL(I).IS .EQ. C) EXIT !Found?
|
||||
END DO !On to the next. A linear search will do.
|
||||
IF (I.LE.0) THEN !Is it identified?
|
||||
TOKENTYPE = HUH !No.
|
||||
INCOMING = SYMBOL(0).PRECEDENCE !And this might provoke a flush.
|
||||
ELSE !If it is identified,
|
||||
TOKENTYPE = I !Then this is a positive number.
|
||||
INCOMING = SYMBOL(I).PRECEDENCE !And this is of interest.
|
||||
END IF !Righto, anything has been identified, possibly as HUH.
|
||||
END IF !So much for classification.
|
||||
END IF !If there is something to see.
|
||||
WRITE (MSG,30) C,INCOMING,TOKENTYPE !Announce.
|
||||
30 FORMAT ("Next=>",A1,"< Prec=",I2,",Ttype=",I2) !C might be blank.
|
||||
END SUBROUTINE FORASIGN !I call for a sign, and I see what?
|
||||
END FUNCTION COMPILE !That's the main activity.
|
||||
END MODULE COMPILER !So, enough of this.
|
||||
ELSE IF (INDEX(BRAOPEN,C).GT.0) THEN !An open bracket?
|
||||
TOKENTYPE = OPENBRA !Yep.
|
||||
ELSE !Otherwise, anything else.
|
||||
DO I = OPSYMBOLS,1,-1 !Scan backwards, to find ** before *, if present.
|
||||
IF (SYMBOL(I).IS .EQ. C) EXIT !Found?
|
||||
END DO !On to the next. A linear search will do.
|
||||
IF (I.LE.0) THEN !Is it identified?
|
||||
TOKENTYPE = HUH !No.
|
||||
INCOMING = SYMBOL(0).PRECEDENCE !And this might provoke a flush.
|
||||
ELSE !If it is identified,
|
||||
TOKENTYPE = I !Then this is a positive number.
|
||||
INCOMING = SYMBOL(I).PRECEDENCE !And this is of interest.
|
||||
END IF !Righto, anything has been identified, possibly as HUH.
|
||||
END IF !So much for classification.
|
||||
END IF !If there is something to see.
|
||||
WRITE (MSG,30) C,INCOMING,TOKENTYPE !Announce.
|
||||
30 FORMAT ("Next=>",A1,"< Prec=",I2,",Ttype=",I2) !C might be blank.
|
||||
END SUBROUTINE FORASIGN !I call for a sign, and I see what?
|
||||
END FUNCTION COMPILE !That's the main activity.
|
||||
END MODULE COMPILER !So, enough of this.
|
||||
|
||||
PROGRAM POKE
|
||||
USE COMPILER
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
Caution! The apparent gaps in the sequence of precedence values in this table are *not* unused!
|
||||
Cunning ploys with precedence allow parameter evaluation, and right-to-left order as in x**y**z.
|
||||
INTEGER OPSYMBOLS !Recognised operator symbols.
|
||||
PARAMETER (OPSYMBOLS = 25) !There are also some associates.
|
||||
TYPE SYMB !To recognise symbols and carry associated information.
|
||||
CHARACTER*2 IS !Its text. Careful with the trailing space and comparisons.
|
||||
INTEGER*1 PRECEDENCE !Controls the order of evaluation.
|
||||
INTEGER*1 POPCOUNT !Stack activity: a+b means + requires two in.
|
||||
CHARACTER*48 USAGE !Description.
|
||||
END TYPE SYMB !The cross-linkage of precedences is tricky.
|
||||
CHARACTER*5 IFPARTS(0:4) !These appear when an operator would otherwise be expected.
|
||||
PARAMETER (IFPARTS = (/"IF","THEN","ELSE","OWISE","FI"/)) !So, bend the usage of "operator".
|
||||
TYPE(SYMB) SYMBOL(-4:OPSYMBOLS) !Righto, I'll have some.
|
||||
PARAMETER (SYMBOL =(/ !Note that "*" is not to be seen as a match to "**".
|
||||
4 SYMB("FI", 2,0,"the FI that ends an IF-statement."), !These negative entries are not for name matching
|
||||
3 SYMB("Ow", 3,0,"the OWISE part of an IF-statement."), !Which is instead done via IFPARTS
|
||||
2 SYMB("El", 3,0,"the ELSE part of an IF-statement."), !But are here to take advantage of the structure in place.
|
||||
1 SYMB("Th", 3,0,"the THEN part of an IF-statement."), !The IF is recognised separately, when expecting an operand.
|
||||
INTEGER OPSYMBOLS !Recognised operator symbols.
|
||||
PARAMETER (OPSYMBOLS = 25) !There are also some associates.
|
||||
TYPE SYMB !To recognise symbols and carry associated information.
|
||||
CHARACTER*2 IS !Its text. Careful with the trailing space and comparisons.
|
||||
INTEGER*1 PRECEDENCE !Controls the order of evaluation.
|
||||
INTEGER*1 POPCOUNT !Stack activity: a+b means + requires two in.
|
||||
CHARACTER*48 USAGE !Description.
|
||||
END TYPE SYMB !The cross-linkage of precedences is tricky.
|
||||
CHARACTER*5 IFPARTS(0:4) !These appear when an operator would otherwise be expected.
|
||||
PARAMETER (IFPARTS = (/"IF","THEN","ELSE","OWISE","FI"/)) !So, bend the usage of "operator".
|
||||
TYPE(SYMB) SYMBOL(-4:OPSYMBOLS) !Righto, I'll have some.
|
||||
PARAMETER (SYMBOL =(/ !Note that "*" is not to be seen as a match to "**".
|
||||
4 SYMB("FI", 2,0,"the FI that ends an IF-statement."), !These negative entries are not for name matching
|
||||
3 SYMB("Ow", 3,0,"the OWISE part of an IF-statement."), !Which is instead done via IFPARTS
|
||||
2 SYMB("El", 3,0,"the ELSE part of an IF-statement."), !But are here to take advantage of the structure in place.
|
||||
1 SYMB("Th", 3,0,"the THEN part of an IF-statement."), !The IF is recognised separately, when expecting an operand.
|
||||
o SYMB(" ", 0,0,"Not recognised as an operator's symbol."),
|
||||
1 SYMB(" ", 1,0,"separates symbols and aids legibility."),
|
||||
C 2 and 3 are used for the parts of an IF-statement. See PRIF.
|
||||
|
|
@ -43,6 +43,6 @@ C SYMB(":=", 6,0,"marks an on-the-fly assignment of a result"), Identified
|
|||
1 SYMB("÷ ",12,2,"division for those with a fancy keyboard."),
|
||||
2 SYMB("\ ",12,2,"remainder a\b = a - truncate(a/b)*b; 11\3 = 2"),
|
||||
C 13 is used so that stacked ** will have lower priority than incoming **, thus delivering right-to-left evaluation.
|
||||
3 SYMB("^ ",14,2,"raise to power: also recognised is **."), !Uses the previous precedence level also!
|
||||
3 SYMB("^ ",14,2,"raise to power: also recognised is **."), !Uses the previous precedence level also!
|
||||
4 SYMB("**",14,2,"raise to power: also recognised is ^."),
|
||||
5 SYMB("! ",15,1,"factorial, sortof, just for fun.")/))
|
||||
|
|
|
|||
|
|
@ -1,84 +1,82 @@
|
|||
(phixonline)-->
|
||||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
|
||||
<span style="color: #004080;">bool</span> <span style="color: #000000;">show_workings</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
|
||||
with javascript_semantics
|
||||
bool show_workings = true
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">operators</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"^"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"*"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"/"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-"</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #000000;">precedence</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span> <span style="color: #0000FF;">}</span>
|
||||
constant operators = {"^","*","/","+","-"},
|
||||
precedence = { 4, 3, 3, 2, 2 }
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">infix</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">rpn</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">sep</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">stack_top</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">stack</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span>
|
||||
<span style="color: #000000;">ops</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">substitute_all</span><span style="color: #0000FF;">(</span><span style="color: #000000;">infix</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"("</span><span style="color: #0000FF;">,</span><span style="color: #008000;">")"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">" ( "</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" ) "</span><span style="color: #0000FF;">}),</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Infix input: %-32s%s"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">infix</span><span style="color: #0000FF;">,</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">show_workings</span><span style="color: #0000FF;">?</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">:</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">)})</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ops</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">op</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ops</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"("</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">stack</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">stack</span><span style="color: #0000FF;">,</span><span style="color: #000000;">op</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">")"</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">stack_top</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">stack</span><span style="color: #0000FF;">[$]</span>
|
||||
<span style="color: #000000;">stack</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">stack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">stack_top</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"("</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">sep</span><span style="color: #0000FF;">&</span><span style="color: #000000;">stack_top</span>
|
||||
<span style="color: #000000;">sep</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">" "</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">op</span><span style="color: #0000FF;">,</span><span style="color: #000000;">operators</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">prec</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">precedence</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">stack</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">stack_top</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">stack</span><span style="color: #0000FF;">[$]</span>
|
||||
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">stack_top</span><span style="color: #0000FF;">,</span><span style="color: #000000;">operators</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #000000;">prec</span><span style="color: #0000FF;">></span><span style="color: #000000;">precedence</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">or</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">prec</span><span style="color: #0000FF;">=</span><span style="color: #000000;">precedence</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">and</span> <span style="color: #000000;">stack_top</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"^"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">exit</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">stack</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">stack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">sep</span><span style="color: #0000FF;">&</span><span style="color: #000000;">stack_top</span>
|
||||
<span style="color: #000000;">sep</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">" "</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #000000;">stack</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">stack</span><span style="color: #0000FF;">,</span><span style="color: #000000;">op</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">sep</span><span style="color: #0000FF;">&</span><span style="color: #000000;">op</span>
|
||||
<span style="color: #000000;">sep</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">" "</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">show_workings</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #0000FF;">?{</span><span style="color: #000000;">op</span><span style="color: #0000FF;">,</span><span style="color: #000000;">stack</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">}</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">stack</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">op</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">stack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">sep</span><span style="color: #0000FF;">&</span><span style="color: #000000;">op</span>
|
||||
<span style="color: #000000;">sep</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">" "</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"result: %-22s [%s]\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">=</span><span style="color: #000000;">rpn</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"ok"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"**ERROR**"</span><span style="color: #0000FF;">)})</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
procedure shunting_yard(string infix, rpn)
|
||||
string res = "", sep = "", stack_top
|
||||
sequence stack = {},
|
||||
ops = split(substitute_all(infix,{"(",")"},{" ( "," ) "}),' ')
|
||||
printf(1,"Infix input: %-32s%s", {infix,iff(show_workings?'\n':' ')})
|
||||
for i=1 to length(ops) do
|
||||
string op = ops[i]
|
||||
if op="(" then
|
||||
stack = append(stack,op)
|
||||
elsif op=")" then
|
||||
while 1 do
|
||||
stack_top = stack[$]
|
||||
stack = stack[1..$-1]
|
||||
if stack_top="(" then exit end if
|
||||
res &= sep&stack_top
|
||||
sep = " "
|
||||
end while
|
||||
else
|
||||
integer k = find(op,operators)
|
||||
if k!=0 then
|
||||
integer prec = precedence[k]
|
||||
while length(stack) do
|
||||
stack_top = stack[$]
|
||||
k = find(stack_top,operators)
|
||||
if k=0 or prec>precedence[k]
|
||||
or (prec=precedence[k] and stack_top="^") then
|
||||
exit
|
||||
end if
|
||||
stack = stack[1..$-1]
|
||||
res &= sep&stack_top
|
||||
sep = " "
|
||||
end while
|
||||
stack = append(stack,op)
|
||||
else
|
||||
res &= sep&op
|
||||
sep = " "
|
||||
end if
|
||||
end if
|
||||
if show_workings then
|
||||
?{op,stack,res}
|
||||
end if
|
||||
end for
|
||||
for i=length(stack) to 1 by -1 do
|
||||
string op = stack[i]
|
||||
res &= sep&op
|
||||
sep = " "
|
||||
end for
|
||||
printf(1,"result: %-22s [%s]\n", {res,iff(res=rpn?"ok","**ERROR**")})
|
||||
end procedure
|
||||
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"3 + 4 * 2 / (1 - 5) ^ 2 ^ 3"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"3 4 2 * 1 5 - 2 3 ^ ^ / +"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">show_workings</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"((1 + 2) ^ (3 + 4)) ^ (5 + 6)"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 2 + 3 4 + ^ 5 6 + ^"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"(1 + 2) ^ (3 + 4) ^ (5 + 6)"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 2 + 3 4 + 5 6 + ^ ^"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"((3 ^ 4) ^ 2 ^ 9) ^ 2 ^ 5"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"3 4 ^ 2 9 ^ ^ 2 5 ^ ^"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"(1 + 4) * (5 + 3) * 2 * 3"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 4 + 5 3 + * 2 * 3 *"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1 * 2 * 3 * 4"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 2 * 3 * 4 *"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1 + 2 + 3 + 4"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 2 + 3 + 4 +"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"(1 + 2) ^ (3 + 4)"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 2 + 3 4 + ^"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"(5 ^ 6) ^ 7"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"5 6 ^ 7 ^"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"5 ^ 4 ^ 3 ^ 2"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"5 4 3 2 ^ ^ ^"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1 + 2 + 3"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 2 + 3 +"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1 ^ 2 ^ 3"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 2 3 ^ ^"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"(1 ^ 2) ^ 3"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 2 ^ 3 ^"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1 - 1 + 3"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 1 - 3 +"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"3 + 1 - 1"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"3 1 + 1 -"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1 - (2 + 3)"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1 2 3 + -"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"4 + 3 + 2"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"4 3 + 2 +"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"5 + 4 + 3 + 2"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"5 4 + 3 + 2 +"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"5 * 4 * 3 * 2"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"5 4 * 3 * 2 *"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"5 + 4 - (3 + 2)"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"5 4 + 3 2 + -"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"3 - 4 * 5"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"3 4 5 * -"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"3 * (4 - 5)"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"3 4 5 - *"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"(3 - 4) * 5"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"3 4 - 5 *"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"4 * 2 + 1 - 5"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"4 2 * 1 + 5 -"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shunting_yard</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"4 * 2 / (1 - 5) ^ 2"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"4 2 * 1 5 - 2 ^ /"</span><span style="color: #0000FF;">)</span>
|
||||
<!--
|
||||
shunting_yard("3 + 4 * 2 / (1 - 5) ^ 2 ^ 3","3 4 2 * 1 5 - 2 3 ^ ^ / +")
|
||||
show_workings = false
|
||||
shunting_yard("((1 + 2) ^ (3 + 4)) ^ (5 + 6)","1 2 + 3 4 + ^ 5 6 + ^")
|
||||
shunting_yard("(1 + 2) ^ (3 + 4) ^ (5 + 6)","1 2 + 3 4 + 5 6 + ^ ^")
|
||||
shunting_yard("((3 ^ 4) ^ 2 ^ 9) ^ 2 ^ 5","3 4 ^ 2 9 ^ ^ 2 5 ^ ^")
|
||||
shunting_yard("(1 + 4) * (5 + 3) * 2 * 3","1 4 + 5 3 + * 2 * 3 *")
|
||||
shunting_yard("1 * 2 * 3 * 4","1 2 * 3 * 4 *")
|
||||
shunting_yard("1 + 2 + 3 + 4","1 2 + 3 + 4 +")
|
||||
shunting_yard("(1 + 2) ^ (3 + 4)","1 2 + 3 4 + ^")
|
||||
shunting_yard("(5 ^ 6) ^ 7","5 6 ^ 7 ^")
|
||||
shunting_yard("5 ^ 4 ^ 3 ^ 2","5 4 3 2 ^ ^ ^")
|
||||
shunting_yard("1 + 2 + 3","1 2 + 3 +")
|
||||
shunting_yard("1 ^ 2 ^ 3","1 2 3 ^ ^")
|
||||
shunting_yard("(1 ^ 2) ^ 3","1 2 ^ 3 ^")
|
||||
shunting_yard("1 - 1 + 3","1 1 - 3 +")
|
||||
shunting_yard("3 + 1 - 1","3 1 + 1 -")
|
||||
shunting_yard("1 - (2 + 3)","1 2 3 + -")
|
||||
shunting_yard("4 + 3 + 2","4 3 + 2 +")
|
||||
shunting_yard("5 + 4 + 3 + 2","5 4 + 3 + 2 +")
|
||||
shunting_yard("5 * 4 * 3 * 2","5 4 * 3 * 2 *")
|
||||
shunting_yard("5 + 4 - (3 + 2)","5 4 + 3 2 + -")
|
||||
shunting_yard("3 - 4 * 5","3 4 5 * -")
|
||||
shunting_yard("3 * (4 - 5)","3 4 5 - *")
|
||||
shunting_yard("(3 - 4) * 5","3 4 - 5 *")
|
||||
shunting_yard("4 * 2 + 1 - 5","4 2 * 1 + 5 -")
|
||||
shunting_yard("4 * 2 / (1 - 5) ^ 2","4 2 * 1 5 - 2 ^ /")
|
||||
|
|
|
|||
|
|
@ -3,198 +3,198 @@ import Foundation
|
|||
|
||||
// Using arrays for both stack and queue
|
||||
struct Stack<T> {
|
||||
private(set) var elements = [T]()
|
||||
|
||||
var isEmpty: Bool {
|
||||
elements.isEmpty
|
||||
}
|
||||
|
||||
var top: T? {
|
||||
elements.last
|
||||
}
|
||||
|
||||
mutating func push(_ newElement: T) {
|
||||
elements.append(newElement)
|
||||
}
|
||||
|
||||
mutating func pop() -> T? {
|
||||
self.isEmpty ? nil : elements.removeLast()
|
||||
}
|
||||
private(set) var elements = [T]()
|
||||
|
||||
var isEmpty: Bool {
|
||||
elements.isEmpty
|
||||
}
|
||||
|
||||
var top: T? {
|
||||
elements.last
|
||||
}
|
||||
|
||||
mutating func push(_ newElement: T) {
|
||||
elements.append(newElement)
|
||||
}
|
||||
|
||||
mutating func pop() -> T? {
|
||||
self.isEmpty ? nil : elements.removeLast()
|
||||
}
|
||||
}
|
||||
|
||||
struct Queue<T> {
|
||||
private(set) var elements = [T]()
|
||||
|
||||
var isEmpty: Bool {
|
||||
elements.isEmpty
|
||||
}
|
||||
|
||||
mutating func enqueue(_ newElement: T) {
|
||||
elements.append(newElement)
|
||||
}
|
||||
|
||||
mutating func dequeue() -> T {
|
||||
return elements.removeFirst()
|
||||
}
|
||||
private(set) var elements = [T]()
|
||||
|
||||
var isEmpty: Bool {
|
||||
elements.isEmpty
|
||||
}
|
||||
|
||||
mutating func enqueue(_ newElement: T) {
|
||||
elements.append(newElement)
|
||||
}
|
||||
|
||||
mutating func dequeue() -> T {
|
||||
return elements.removeFirst()
|
||||
}
|
||||
}
|
||||
|
||||
enum Associativity {
|
||||
case Left, Right
|
||||
case Left, Right
|
||||
}
|
||||
|
||||
// Protocol can be used to restrict Set extension
|
||||
protocol OperatorType: Comparable, Hashable {
|
||||
var name: String { get }
|
||||
var precedence: Int { get }
|
||||
var associativity: Associativity { get }
|
||||
var name: String { get }
|
||||
var precedence: Int { get }
|
||||
var associativity: Associativity { get }
|
||||
}
|
||||
|
||||
struct Operator: OperatorType {
|
||||
let name: String
|
||||
let precedence: Int
|
||||
let associativity: Associativity
|
||||
|
||||
// Duplicate operator names are not allowed
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(self.name)
|
||||
}
|
||||
|
||||
init(_ name: String, _ precedence: Int, _ associativity: Associativity) {
|
||||
self.name = name; self.precedence = precedence; self.associativity = associativity
|
||||
}
|
||||
let name: String
|
||||
let precedence: Int
|
||||
let associativity: Associativity
|
||||
|
||||
// Duplicate operator names are not allowed
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(self.name)
|
||||
}
|
||||
|
||||
init(_ name: String, _ precedence: Int, _ associativity: Associativity) {
|
||||
self.name = name; self.precedence = precedence; self.associativity = associativity
|
||||
}
|
||||
}
|
||||
|
||||
func ==(x: Operator, y: Operator) -> Bool {
|
||||
// Identified by name
|
||||
x.name == y.name
|
||||
// Identified by name
|
||||
x.name == y.name
|
||||
}
|
||||
|
||||
func <(x: Operator, y: Operator) -> Bool {
|
||||
// Take precedence and associavity into account
|
||||
(x.associativity == .Left && x.precedence == y.precedence) || x.precedence < y.precedence
|
||||
// Take precedence and associavity into account
|
||||
(x.associativity == .Left && x.precedence == y.precedence) || x.precedence < y.precedence
|
||||
}
|
||||
|
||||
extension Set where Element: OperatorType {
|
||||
func contains(_ operatorName: String) -> Bool {
|
||||
contains { $0.name == operatorName }
|
||||
}
|
||||
|
||||
subscript (operatorName: String) -> Element? {
|
||||
get {
|
||||
filter { $0.name == operatorName }.first
|
||||
}
|
||||
}
|
||||
func contains(_ operatorName: String) -> Bool {
|
||||
contains { $0.name == operatorName }
|
||||
}
|
||||
|
||||
subscript (operatorName: String) -> Element? {
|
||||
get {
|
||||
filter { $0.name == operatorName }.first
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience
|
||||
extension String {
|
||||
var isNumber: Bool { return Double(self) != nil }
|
||||
var isNumber: Bool { return Double(self) != nil }
|
||||
}
|
||||
|
||||
struct ShuntingYard {
|
||||
enum ParseError: Error {
|
||||
case MismatchedParenthesis(parenthesis: String, expression: String)
|
||||
case UnrecognizedToken(token: String, expression: String)
|
||||
case ExtraneousToken(token: String, expression: String)
|
||||
}
|
||||
|
||||
static func parse(_ input: String, operators: Set<Operator>) throws -> String {
|
||||
var stack = Stack<String>()
|
||||
var output = Queue<String>()
|
||||
let tokens = input.components(separatedBy: " ")
|
||||
|
||||
for token in tokens {
|
||||
// Number?
|
||||
if token.isNumber {
|
||||
// Add it to the output queue
|
||||
output.enqueue(token)
|
||||
continue
|
||||
}
|
||||
|
||||
// Operator?
|
||||
if operators.contains(token) {
|
||||
// While there is a operator on top of the stack and has lower precedence than current operator (token)
|
||||
while let top = stack.top,
|
||||
operators.contains(top) && Self.hasLowerPrecedence(token, top, operators) {
|
||||
// Pop it off to the output queue
|
||||
output.enqueue(stack.pop()!)
|
||||
}
|
||||
// Push current operator (token) onto the operator stack
|
||||
stack.push(token)
|
||||
continue
|
||||
}
|
||||
|
||||
// Left parenthesis?
|
||||
if token == "(" {
|
||||
// Push it onto the stack
|
||||
stack.push(token)
|
||||
continue
|
||||
}
|
||||
|
||||
// Right parenthesis?
|
||||
if token == ")" {
|
||||
// Until the token at the top of the stack is a left parenthesis
|
||||
while let top = stack.top, top != "(" {
|
||||
// Pop operators off the stack onto the output queue.
|
||||
output.enqueue(stack.pop()!)
|
||||
}
|
||||
|
||||
// Pop the left parenthesis from the stack without putting it onto the output queue
|
||||
guard let _ = stack.pop() else {
|
||||
// If the stack runs out, than there is no matching left parenthesis
|
||||
throw ParseError.MismatchedParenthesis(parenthesis: ")", expression: input)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Token not recognized!
|
||||
throw ParseError.UnrecognizedToken(token: token, expression: token)
|
||||
}
|
||||
|
||||
// No more tokens
|
||||
|
||||
// Still operators on the stack?
|
||||
while let top = stack.top,
|
||||
operators.contains(top) {
|
||||
// Put them onto the output queue
|
||||
output.enqueue(stack.pop()!)
|
||||
}
|
||||
|
||||
// If the top of the stack is a (left) parenthesis, then there is no matching right parenthesis
|
||||
// Note: Assume that all operators has been popped and put onto the output queue
|
||||
if let top = stack.pop() {
|
||||
throw (
|
||||
top == "("
|
||||
? ParseError.MismatchedParenthesis(parenthesis: "(", expression: input)
|
||||
: ParseError.ExtraneousToken(token: top, expression: input)
|
||||
)
|
||||
}
|
||||
|
||||
return output.elements.joined(separator: " ")
|
||||
}
|
||||
|
||||
static private func hasLowerPrecedence(_ firstToken: String, _ secondToken: String, _ operators: Set<Operator>) -> Bool {
|
||||
guard let firstOperator = operators[firstToken],
|
||||
let secondOperator = operators[secondToken] else {
|
||||
return false
|
||||
}
|
||||
|
||||
return firstOperator < secondOperator
|
||||
}
|
||||
enum ParseError: Error {
|
||||
case MismatchedParenthesis(parenthesis: String, expression: String)
|
||||
case UnrecognizedToken(token: String, expression: String)
|
||||
case ExtraneousToken(token: String, expression: String)
|
||||
}
|
||||
|
||||
static func parse(_ input: String, operators: Set<Operator>) throws -> String {
|
||||
var stack = Stack<String>()
|
||||
var output = Queue<String>()
|
||||
let tokens = input.components(separatedBy: " ")
|
||||
|
||||
for token in tokens {
|
||||
// Number?
|
||||
if token.isNumber {
|
||||
// Add it to the output queue
|
||||
output.enqueue(token)
|
||||
continue
|
||||
}
|
||||
|
||||
// Operator?
|
||||
if operators.contains(token) {
|
||||
// While there is a operator on top of the stack and has lower precedence than current operator (token)
|
||||
while let top = stack.top,
|
||||
operators.contains(top) && Self.hasLowerPrecedence(token, top, operators) {
|
||||
// Pop it off to the output queue
|
||||
output.enqueue(stack.pop()!)
|
||||
}
|
||||
// Push current operator (token) onto the operator stack
|
||||
stack.push(token)
|
||||
continue
|
||||
}
|
||||
|
||||
// Left parenthesis?
|
||||
if token == "(" {
|
||||
// Push it onto the stack
|
||||
stack.push(token)
|
||||
continue
|
||||
}
|
||||
|
||||
// Right parenthesis?
|
||||
if token == ")" {
|
||||
// Until the token at the top of the stack is a left parenthesis
|
||||
while let top = stack.top, top != "(" {
|
||||
// Pop operators off the stack onto the output queue.
|
||||
output.enqueue(stack.pop()!)
|
||||
}
|
||||
|
||||
// Pop the left parenthesis from the stack without putting it onto the output queue
|
||||
guard let _ = stack.pop() else {
|
||||
// If the stack runs out, than there is no matching left parenthesis
|
||||
throw ParseError.MismatchedParenthesis(parenthesis: ")", expression: input)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Token not recognized!
|
||||
throw ParseError.UnrecognizedToken(token: token, expression: token)
|
||||
}
|
||||
|
||||
// No more tokens
|
||||
|
||||
// Still operators on the stack?
|
||||
while let top = stack.top,
|
||||
operators.contains(top) {
|
||||
// Put them onto the output queue
|
||||
output.enqueue(stack.pop()!)
|
||||
}
|
||||
|
||||
// If the top of the stack is a (left) parenthesis, then there is no matching right parenthesis
|
||||
// Note: Assume that all operators has been popped and put onto the output queue
|
||||
if let top = stack.pop() {
|
||||
throw (
|
||||
top == "("
|
||||
? ParseError.MismatchedParenthesis(parenthesis: "(", expression: input)
|
||||
: ParseError.ExtraneousToken(token: top, expression: input)
|
||||
)
|
||||
}
|
||||
|
||||
return output.elements.joined(separator: " ")
|
||||
}
|
||||
|
||||
static private func hasLowerPrecedence(_ firstToken: String, _ secondToken: String, _ operators: Set<Operator>) -> Bool {
|
||||
guard let firstOperator = operators[firstToken],
|
||||
let secondOperator = operators[secondToken] else {
|
||||
return false
|
||||
}
|
||||
|
||||
return firstOperator < secondOperator
|
||||
}
|
||||
}
|
||||
|
||||
/* Include in tests
|
||||
func testParse() throws {
|
||||
let input = "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3"
|
||||
let operators: Set<Operator> = [
|
||||
Operator("^", 4, .Right),
|
||||
Operator("*", 3, .Left),
|
||||
Operator("/", 3, .Left),
|
||||
Operator("+", 2, .Left),
|
||||
Operator("-", 2, .Left)
|
||||
]
|
||||
let output = try! ShuntingYard.parse(input, operators: operators)
|
||||
XCTAssertEqual(output, "3 4 2 * 1 5 - 2 3 ^ ^ / +")
|
||||
let input = "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3"
|
||||
let operators: Set<Operator> = [
|
||||
Operator("^", 4, .Right),
|
||||
Operator("*", 3, .Left),
|
||||
Operator("/", 3, .Left),
|
||||
Operator("+", 2, .Left),
|
||||
Operator("-", 2, .Left)
|
||||
]
|
||||
let output = try! ShuntingYard.parse(input, operators: operators)
|
||||
XCTAssertEqual(output, "3 4 2 * 1 5 - 2 3 ^ ^ / +")
|
||||
}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -14,42 +14,42 @@ proc associativity op {
|
|||
proc shunting {expression} {
|
||||
set stack {}
|
||||
foreach token [tokenize $expression] {
|
||||
if {[string is double $token]} {
|
||||
puts "add to output: $token"
|
||||
lappend output $token
|
||||
} elseif {$token eq "("} {
|
||||
puts "push parenthesis"
|
||||
lappend stack $token
|
||||
} elseif {$token eq ")"} {
|
||||
puts "popping to parenthesis"
|
||||
while {[lindex $stack end] ne "("} {
|
||||
lappend output [lindex $stack end]
|
||||
set stack [lreplace $stack end end]
|
||||
puts "...popped [lindex $output end] to output"
|
||||
}
|
||||
set stack [lreplace $stack end end]
|
||||
puts "...found parenthesis"
|
||||
} else {
|
||||
puts "adding operator: $token"
|
||||
set p [precedence $token]
|
||||
set a [associativity $token]
|
||||
while {[llength $stack]} {
|
||||
set o2 [lindex $stack end]
|
||||
if {
|
||||
$o2 ne "(" &&
|
||||
(($a eq "left" && $p <= [precedence $o2]) ||
|
||||
($a eq "right" && $p < [precedence $o2]))
|
||||
} then {
|
||||
puts "...popped operator $o2 to output"
|
||||
lappend output $o2
|
||||
set stack [lreplace $stack end end]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
lappend stack $token
|
||||
}
|
||||
puts "\t\tOutput:\t$output\n\t\tStack:\t$stack"
|
||||
if {[string is double $token]} {
|
||||
puts "add to output: $token"
|
||||
lappend output $token
|
||||
} elseif {$token eq "("} {
|
||||
puts "push parenthesis"
|
||||
lappend stack $token
|
||||
} elseif {$token eq ")"} {
|
||||
puts "popping to parenthesis"
|
||||
while {[lindex $stack end] ne "("} {
|
||||
lappend output [lindex $stack end]
|
||||
set stack [lreplace $stack end end]
|
||||
puts "...popped [lindex $output end] to output"
|
||||
}
|
||||
set stack [lreplace $stack end end]
|
||||
puts "...found parenthesis"
|
||||
} else {
|
||||
puts "adding operator: $token"
|
||||
set p [precedence $token]
|
||||
set a [associativity $token]
|
||||
while {[llength $stack]} {
|
||||
set o2 [lindex $stack end]
|
||||
if {
|
||||
$o2 ne "(" &&
|
||||
(($a eq "left" && $p <= [precedence $o2]) ||
|
||||
($a eq "right" && $p < [precedence $o2]))
|
||||
} then {
|
||||
puts "...popped operator $o2 to output"
|
||||
lappend output $o2
|
||||
set stack [lreplace $stack end end]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
lappend stack $token
|
||||
}
|
||||
puts "\t\tOutput:\t$output\n\t\tStack:\t$stack"
|
||||
}
|
||||
puts "transferring tokens from stack to output"
|
||||
lappend output {*}[lreverse $stack]
|
||||
|
|
|
|||
|
|
@ -1,48 +1,48 @@
|
|||
Token: 3
|
||||
Output: 3
|
||||
Operators:
|
||||
Output: 3
|
||||
Operators:
|
||||
Token: +
|
||||
Output: 3
|
||||
Operators: +
|
||||
Output: 3
|
||||
Operators: +
|
||||
Token: 4
|
||||
Output: 3 4
|
||||
Operators: +
|
||||
Output: 3 4
|
||||
Operators: +
|
||||
Token: *
|
||||
Output: 3 4
|
||||
Operators: + *
|
||||
Output: 3 4
|
||||
Operators: + *
|
||||
Token: 2
|
||||
Output: 3 4 2
|
||||
Operators: + *
|
||||
Output: 3 4 2
|
||||
Operators: + *
|
||||
Token: /
|
||||
Output: 3 4 2
|
||||
Operators: + * /
|
||||
Output: 3 4 2
|
||||
Operators: + * /
|
||||
Token: (
|
||||
Output: 3 4 2
|
||||
Operators: + * / (
|
||||
Output: 3 4 2
|
||||
Operators: + * / (
|
||||
Token: 1
|
||||
Output: 3 4 2 1
|
||||
Operators: + * / (
|
||||
Output: 3 4 2 1
|
||||
Operators: + * / (
|
||||
Token: -
|
||||
Output: 3 4 2 1
|
||||
Operators: + * / ( -
|
||||
Output: 3 4 2 1
|
||||
Operators: + * / ( -
|
||||
Token: 5
|
||||
Output: 3 4 2 1 5
|
||||
Operators: + * / ( -
|
||||
Output: 3 4 2 1 5
|
||||
Operators: + * / ( -
|
||||
Token: )
|
||||
Output: 3 4 2 1 5 -
|
||||
Operators: + * /
|
||||
Output: 3 4 2 1 5 -
|
||||
Operators: + * /
|
||||
Token: ^
|
||||
Output: 3 4 2 1 5 -
|
||||
Operators: + * / ^
|
||||
Output: 3 4 2 1 5 -
|
||||
Operators: + * / ^
|
||||
Token: 2
|
||||
Output: 3 4 2 1 5 - 2
|
||||
Operators: + * / ^
|
||||
Output: 3 4 2 1 5 - 2
|
||||
Operators: + * / ^
|
||||
Token: ^
|
||||
Output: 3 4 2 1 5 - 2
|
||||
Operators: + * / ^ ^
|
||||
Output: 3 4 2 1 5 - 2
|
||||
Operators: + * / ^ ^
|
||||
Token: 3
|
||||
Output: 3 4 2 1 5 - 2 3
|
||||
Operators: + * / ^ ^
|
||||
Output: 3 4 2 1 5 - 2 3
|
||||
Operators: + * / ^ ^
|
||||
End parsing
|
||||
Output: 3 4 2 1 5 - 2 3 ^ ^ / * +
|
||||
Operators:
|
||||
Output: 3 4 2 1 5 - 2 3 ^ ^ / * +
|
||||
Operators:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
var input="3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3";
|
||||
|
||||
var opa=Dictionary("^",T(4,True), "*",T(3,False), // op:(prec,rAssoc)
|
||||
"/",T(3,False), "+",T(2,False), "-",T(2,False),
|
||||
"/",T(3,False), "+",T(2,False), "-",T(2,False),
|
||||
);
|
||||
|
||||
"infix: ".println(input);
|
||||
|
|
@ -13,30 +13,30 @@ fcn parseInfix(e){
|
|||
foreach tok in (e.split(" ")){
|
||||
switch(tok){
|
||||
case("("){ stack.append(tok) } // push "(" to stack
|
||||
case(")"){
|
||||
case(")"){
|
||||
while(True){ // pop item ("(" or operator) from stack
|
||||
op:=stack.pop();
|
||||
if(op=="(") break; // discard "("
|
||||
rpn+=" " + op; // add operator to result
|
||||
}
|
||||
}
|
||||
if(op=="(") break; // discard "("
|
||||
rpn+=" " + op; // add operator to result
|
||||
}
|
||||
}
|
||||
else{ // default
|
||||
o1:=opa.find(tok); // op or Void
|
||||
if(o1){ // token is an operator
|
||||
while(stack){
|
||||
o1:=opa.find(tok); // op or Void
|
||||
if(o1){ // token is an operator
|
||||
while(stack){
|
||||
// consider top item on stack
|
||||
op:=stack[-1]; o2:=opa.find(op);
|
||||
if(not o2 or o1[0]>o2[0] or
|
||||
op:=stack[-1]; o2:=opa.find(op);
|
||||
if(not o2 or o1[0]>o2[0] or
|
||||
(o1[0]==o2[0] and o1[1])) break;
|
||||
// top item is an operator that needs to come off
|
||||
stack.pop();
|
||||
rpn+=" " + op; // add it to result
|
||||
}
|
||||
// push operator (the new one) to stack
|
||||
stack.append(tok);
|
||||
}else // token is an operand
|
||||
rpn+=(rpn and " " or "") + tok; // add operand to result
|
||||
}
|
||||
// top item is an operator that needs to come off
|
||||
stack.pop();
|
||||
rpn+=" " + op; // add it to result
|
||||
}
|
||||
// push operator (the new one) to stack
|
||||
stack.append(tok);
|
||||
}else // token is an operand
|
||||
rpn+=(rpn and " " or "") + tok; // add operand to result
|
||||
}
|
||||
} // switch
|
||||
display(tok,rpn,stack);
|
||||
} // foreach
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue