tasks a-s

This commit is contained in:
Ingy döt Net 2013-04-10 23:57:08 -07:00
parent 47bf37c096
commit b83f433714
12433 changed files with 156208 additions and 123 deletions

View file

@ -0,0 +1,37 @@
Create a program that takes an [[wp:Reverse Polish notation|RPN]] representation of an expression formatted as a space separated sequence of tokens and generates the equivalent expression in [[wp:Infix notation|infix notation]].
* Assume an input of a correct, space separated, string of tokens
* Generate a space separated output string representing the same expression in infix notation
* Show how the major datastructure of your algorithm changes with each new token parsed.
* Test with the following input RPN strings then print and display the output here.
:{| class="wikitable"
! RPN input !! sample output
|- || align="center"
| <code>3 4 2 * 1 5 - 2 3 ^ ^ / +</code>|| <code>3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3</code>
|- || align="center"
| <code>1 2 + 3 4 + ^ 5 6 + ^</code>|| <code>( ( 1 + 2 ) ^ ( 3 + 4 ) ) ^ ( 5 + 6 )</code>
|}
* Operator precedence is given in this table:
:{| class="wikitable"
! operator !! [[wp:Order_of_operations|precedence]] !! [[wp:Operator_associativity|associativity]]
|- || align="center"
| ^ || 4 || Right
|- || align="center"
| * || 3 || Left
|- || align="center"
| / || 3 || Left
|- || align="center"
| + || 2 || Left
|- || align="center"
| - || 2 || Left
|}
;Note:
* '^' means exponentiation.
;See also:
* [[Parsing/Shunting-yard algorithm]] for a method of generating an RPN from an infix expression.
* [[Parsing/RPN calculator algorithm]] for a method of calculating a final value from this output RPN expression.
* [http://www.rubyquiz.com/quiz148.html Postfix to infix] from the RubyQuiz site.

View file

@ -0,0 +1,102 @@
#!/usr/bin/awk -f
BEGIN {
initStack()
initOpers()
print "Infix: " toInfix("3 4 2 * 1 5 - 2 3 ^ ^ / +")
print ""
print "Infix: " toInfix("1 2 + 3 4 + ^ 5 6 + ^")
print ""
print "Infix: " toInfix("moon stars mud + * fire soup * ^")
exit
}
function initStack() {
delete stack
stackPtr = 0
}
function initOpers() {
VALPREC = "9"
LEFT = "l"
RIGHT = "r"
operToks = "+" "-" "/" "*" "^"
operPrec = "2" "2" "3" "3" "4"
operAssoc = LEFT LEFT LEFT LEFT RIGHT
}
function toInfix(rpn, t, toks, tok, a, ap, b, bp, tp, ta) {
print "Postfix: " rpn
split(rpn, toks, / +/)
for (t = 1; t <= length(toks); t++) {
tok = toks[t]
if (!isOper(tok)) {
push(VALPREC tok)
}
else {
b = pop()
bp = prec(b)
b = tail(b)
a = pop()
ap = prec(a)
a = tail(a)
tp = tokPrec(tok)
ta = tokAssoc(tok)
if (ap < tp || (ap == tp && ta == RIGHT)) {
a = "(" a ")"
}
if (bp < tp || (bp == tp && ta == LEFT)) {
b = "(" b ")"
}
push(tp a " " tok " " b)
}
print " " tok " -> " stackToStr()
}
return tail(pop())
}
function push(expr) {
stack[stackPtr] = expr
stackPtr++
}
function pop() {
stackPtr--
return stack[stackPtr]
}
function isOper(tok) {
return index(operToks, tok) != 0
}
function prec(expr) {
return substr(expr, 1, 1)
}
function tokPrec(tok) {
return substr(operPrec, operIdx(tok), 1)
}
function tokAssoc(tok) {
return substr(operAssoc, operIdx(tok), 1)
}
function operIdx(tok) {
return index(operToks, tok)
}
function tail(s) {
return substr(s, 2)
}
function stackToStr( s, i, t, p) {
s = ""
for (i = 0; i < stackPtr; i++) {
t = stack[i]
p = prec(t)
if (index(t, " ")) t = "{" tail(t) "}"
else t = tail(t)
s = s "{" p " " t "} "
}
return s
}

View file

@ -0,0 +1,82 @@
type Priority is range 1..4;
type Infix is record
Precedence : Priority;
Expression : Unbounded_String;
end record;
package Expression_Stack is new Generic_Stack (Infix);
use Expression_Stack;
function Convert (RPN : String) return String is
Arguments : Stack;
procedure Pop
( Operation : Character;
Precedence : Priority;
Association : Priority
) is
Right, Left : Infix;
Result : Infix;
begin
Pop (Right, Arguments);
Pop (Left, Arguments);
Result.Precedence := Association;
if Left.Precedence < Precedence then
Append (Result.Expression, '(');
Append (Result.Expression, Left.Expression);
Append (Result.Expression, ')');
else
Append (Result.Expression, Left.Expression);
end if;
Append (Result.Expression, ' ');
Append (Result.Expression, Operation);
Append (Result.Expression, ' ');
if Right.Precedence < Precedence then
Append (Result.Expression, '(');
Append (Result.Expression, Right.Expression);
Append (Result.Expression, ')');
else
Append (Result.Expression, Right.Expression);
end if;
Push (Result, Arguments);
end Pop;
Pointer : Integer := RPN'First;
begin
while Pointer <= RPN'Last loop
case RPN (Pointer) is
when ' ' =>
Pointer := Pointer + 1;
when '0'..'9' =>
declare
Start : constant Integer := Pointer;
begin
loop
Pointer := Pointer + 1;
exit when Pointer > RPN'Last
or else RPN (Pointer) not in '0'..'9';
end loop;
Push
( ( 4,
To_Unbounded_String (RPN (Start..Pointer - 1))
),
Arguments
);
end;
when '+' | '-' =>
Pop (RPN (Pointer), 1, 1);
Pointer := Pointer + 1;
when '*' | '/' =>
Pop (RPN (Pointer), 2, 2);
Pointer := Pointer + 1;
when '^' =>
Pop (RPN (Pointer), 4, 3);
Pointer := Pointer + 1;
when others =>
raise Constraint_Error with "Syntax";
end case;
end loop;
declare
Result : Infix;
begin
Pop (Result, Arguments);
return To_String (Result.Expression);
end;
end Convert;

View file

@ -0,0 +1,12 @@
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO; use Ada.Text_IO;
with Generic_Stack;
procedure RPN_to_Infix is
-- The code above
begin
Put_Line ("3 4 2 * 1 5 - 2 3 ^ ^ / + = ");
Put_Line (Convert ("3 4 2 * 1 5 - 2 3 ^ ^ / +"));
Put_Line ("1 2 + 3 4 + ^ 5 6 + ^ = ");
Put_Line (Convert ("1 2 + 3 4 + ^ 5 6 + ^"));
end RPN_to_Infix;

View file

@ -0,0 +1,46 @@
expr := "3 4 2 * 1 5 - 2 3 ^ ^ / +"
stack := {push: func("ObjInsert"), pop: func("ObjRemove")}
out := "TOKEN`tACTION STACK (comma separated)`r`n"
Loop Parse, expr, %A_Space%
{
token := A_LoopField
if token is number
stack.push([0, token])
if isOp(token)
{
b := stack.pop(), a := stack.pop(), p := b.1 > a.1 ? b.1 : a.1
p := Precedence(token) > p ? precedence(token) : p
if (a.1 < b.1) and isRight(token)
stack.push([p, "( " . a.2 " ) " token " " b.2])
else if (a.1 > b.1) and isLeft(token)
stack.push([p, a.2 token " ( " b.2 " ) "])
else
stack.push([p, a.2 . " " . token . " " . b.2])
}
out .= token "`t" (isOp(token) ? "Push Partial expression "
: "Push num" space(16)) disp(stack) "`r`n"
}
out .= "`r`n The final output infix expression is: '" disp(stack) "'"
clipboard := out
isOp(t){
return (!!InStr("+-*/^", t) && t)
}
IsLeft(o){
return !!InStr("*/+-", o)
}
IsRight(o){
return o = "^"
}
Precedence(o){
return (InStr("+-/*^", o)+3)//2
}
Disp(obj){
for each, val in obj
if val[2]
o .= ", " val[2]
return SubStr(o,3)
}
Space(n){
return n>0 ? A_Space Space(n-1) : ""
}

View file

@ -0,0 +1,43 @@
import std.stdio, std.string, std.array;
void parseRPN(in string e) {
enum nPrec = 9;
static struct Info { int prec; bool rAssoc; }
immutable /*static*/ opa = ["^": Info(4, true),
"*": Info(3, false),
"/": Info(3, false),
"+": Info(2, false),
"-": Info(2, false)];
writeln("\nPostfix input: ", e);
static struct Sf { int prec; string expr; }
Sf[] stack;
foreach (immutable tok; e.split()) {
writeln("Token: ", tok);
if (tok in opa) {
immutable op = opa[tok];
immutable rhs = stack.back;
stack.popBack();
auto lhs = &stack.back;
if (lhs.prec < op.prec ||
(lhs.prec == op.prec && op.rAssoc))
lhs.expr = "(" ~ lhs.expr ~ ")";
lhs.expr ~= " " ~ tok ~ " ";
lhs.expr ~= (rhs.prec < op.prec ||
(rhs.prec == op.prec && !op.rAssoc)) ?
"(" ~ rhs.expr ~ ")" :
rhs.expr;
lhs.prec = op.prec;
} else
stack ~= Sf(nPrec, tok);
foreach (immutable f; stack)
writefln(` %d "%s"`, f.prec, f.expr);
}
writeln("Infix result: ", stack[0].expr);
}
void main() {
foreach (immutable test; ["3 4 2 * 1 5 - 2 3 ^ ^ / +",
"1 2 + 3 4 + ^ 5 6 + ^"])
parseRPN(test);
}

View file

@ -0,0 +1,63 @@
package main
import (
"fmt"
"strings"
)
var tests = []string{
"3 4 2 * 1 5 - 2 3 ^ ^ / +",
"1 2 + 3 4 + ^ 5 6 + ^",
}
var opa = map[string]struct {
prec int
rAssoc bool
}{
"^": {4, true},
"*": {3, false},
"/": {3, false},
"+": {2, false},
"-": {2, false},
}
const nPrec = 9
func main() {
for _, t := range tests {
parseRPN(t)
}
}
func parseRPN(e string) {
fmt.Println("\npostfix:", e)
type sf struct {
prec int
expr string
}
var stack []sf
for _, tok := range strings.Fields(e) {
fmt.Println("token:", tok)
if op, isOp := opa[tok]; isOp {
rhs := &stack[len(stack)-1]
stack = stack[:len(stack)-1]
lhs := &stack[len(stack)-1]
if lhs.prec < op.prec || (lhs.prec == op.prec && op.rAssoc) {
lhs.expr = "(" + lhs.expr + ")"
}
lhs.expr += " " + tok + " "
if rhs.prec < op.prec || (rhs.prec == op.prec && !op.rAssoc) {
lhs.expr += "(" + rhs.expr + ")"
} else {
lhs.expr += rhs.expr
}
lhs.prec = op.prec
} else {
stack = append(stack, sf{nPrec, tok})
}
for _, f := range stack {
fmt.Printf(" %d %q\n", f.prec, f.expr)
}
}
fmt.Println("infix:", stack[0].expr)
}

View file

@ -0,0 +1,58 @@
procedure main()
every rpn := ![
"3 4 2 * 1 5 - 2 3 ^ ^ / +", # reqd
"1 2 + 3 4 + 5 6 + ^ ^",
"1 2 + 3 4 + 5 6 + ^ ^",
"1 2 + 3 4 + ^ 5 6 + ^" # reqd
] do {
printf("\nRPN = %i\n",rpn)
printf("infix = %i\n",RPN2Infix(rpn,show))
show := 1 # turn off inner working display
}
end
link printf
procedure RPN2Infix(expr,show) #: RPN to Infix conversion
static oi
initial {
oi := table([9,"'"]) # precedence & associativity
every oi[!"+-"] := [2,"l"] # 2L
every oi[!"*/"] := [3,"l"] # 3L
oi["^"] := [4,"r"] # 4R
}
show := if /show then printf else 1 # to show inner workings or not
stack := []
expr ? until pos(0) do { # Reformat as a tree
tab(many(' ')) # consume previous seperator
token := tab(upto(' ')|0) # get token
if token := numeric(token) then { # ... numeric
push(stack,oi[token]|||[token])
show("pushed numeric %i : %s\n",token,list2string(stack))
}
else { # ... operator
every b|a := pop(stack) # pop & reverse operands
pr := oi[token,1]
as := oi[token,2]
if a[1] < pr | (a[1] = pr & oi[token,2] == "r") then
a[3] := sprintf("( %s )",a[3])
if b[1] < pr | (b[1] == pr & oi[token,2] == "l") then
b[3] := sprintf("( %s )",b[3])
s := sprintf("%s %s %s",a[3],token,b[3])
push(stack,[pr,as,s]) # stack [prec, assoc, expr]
show("applied operator %s : %s\n",token,list2string(stack))
}
}
if *stack ~= 1 then stop("Parser failure")
return stack[1,3]
end
procedure list2string(L) #: format list as a string
s := "[ "
every x := !L do
s ||:= ( if type(x) == "list" then list2string(x)
else x) || " "
return s || "]"
end

View file

@ -0,0 +1,36 @@
tokenize=: ' ' <;._1@, deb
ops=: ;:'+ - * / ^'
doOp=: plus`minus`times`divide`exponent`push@.(ops&i.)
parse=:3 :0
stack=: i.0 2
for_token.tokenize y do.doOp token end.
1{:: ,stack
)
parens=:4 :0
if. y do. '( ',x,' )' else. x end.
)
NB. m: precedence, n: is right associative, y: token
op=:2 :0
L=. m - n
R=. m - -.n
smoutput;'operation: ';y
'Lprec left Rprec right'=. ,_2{.stack
expr=. ;(left parens L > Lprec);' ';y,' ';right parens R > Rprec
stack=: (_2}.stack),m;expr
smoutput stack
)
plus=: 2 op 0
minus=: 2 op 0
times=: 3 op 0
divide=: 3 op 0
exponent=: 4 op 1
push=:3 :0
smoutput;'pushing: ';y
stack=: stack,_;y
smoutput stack
)

View file

@ -0,0 +1,102 @@
parse '3 4 2 * 1 5 - 2 3 ^ ^ / +'
pushing: 3
+-+-+
|_|3|
+-+-+
pushing: 4
+-+-+
|_|3|
+-+-+
|_|4|
+-+-+
pushing: 2
+-+-+
|_|3|
+-+-+
|_|4|
+-+-+
|_|2|
+-+-+
operation: *
+-+-----+
|_|3 |
+-+-----+
|3|4 * 2|
+-+-----+
pushing: 1
+-+-----+
|_|3 |
+-+-----+
|3|4 * 2|
+-+-----+
|_|1 |
+-+-----+
pushing: 5
+-+-----+
|_|3 |
+-+-----+
|3|4 * 2|
+-+-----+
|_|1 |
+-+-----+
|_|5 |
+-+-----+
operation: -
+-+-----+
|_|3 |
+-+-----+
|3|4 * 2|
+-+-----+
|2|1 - 5|
+-+-----+
pushing: 2
+-+-----+
|_|3 |
+-+-----+
|3|4 * 2|
+-+-----+
|2|1 - 5|
+-+-----+
|_|2 |
+-+-----+
pushing: 3
+-+-----+
|_|3 |
+-+-----+
|3|4 * 2|
+-+-----+
|2|1 - 5|
+-+-----+
|_|2 |
+-+-----+
|_|3 |
+-+-----+
operation: ^
+-+-----+
|_|3 |
+-+-----+
|3|4 * 2|
+-+-----+
|2|1 - 5|
+-+-----+
|4|2 ^ 3|
+-+-----+
operation: ^
+-+-----------------+
|_|3 |
+-+-----------------+
|3|4 * 2 |
+-+-----------------+
|4|( 1 - 5 ) ^ 2 ^ 3|
+-+-----------------+
operation: /
+-+-------------------------+
|_|3 |
+-+-------------------------+
|3|4 * 2 / ( 1 - 5 ) ^ 2 ^ 3|
+-+-------------------------+
operation: +
+-+-----------------------------+
|2|3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3|
+-+-----------------------------+
3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3

View file

@ -0,0 +1,54 @@
/* Uses a push-down pop-up stack for the stack (instead of array) */
cvt: procedure options (main); /* 10 Sept. 2012 */
declare (true initial ('1'b), false initial ('0'b) ) bit (1);
declare list character (1) controlled, written bit (1) controlled;
declare (RPN, out) character (100) varying;
declare s character (1);
declare input_priority (5) fixed (1) static initial (1, 1, 2, 2, 3);
declare stack_priority (5) fixed (1) static initial (1, 1, 2, 2, 4);
declare (i, ki, kl) fixed binary;
put ('Convert a Reverse Polish expression to orthodox.');
put skip list ('Enclose the expression in apostrophes:');
get list (RPN);
put skip list ('The original Reverse Polish expression = ' || RPN);
out = '';
allocate list, written;
list = substr(RPN, length(RPN), 1); written = false;
translation:
do i = length (RPN)-1 to 1 by -1;
s = substr(RPN, i, 1);
if s = ' ' then iterate;
ki = index('+-*/^', s);
kl = index('+-*/^', list);
if ki > 0 then /* we have an operator */
do;
if input_priority (ki) < stack_priority (kl) then
do; /* transfer ')' to list, then operator. */
allocate list, written;
list = '('; written = false;
out = ')' || out;
end;
allocate list, written;
list = s; written = false;
end;
else /* It's a variable name */
do;
out = s || out;
next_list:
if allocation(list) > 0 then if written then free written, list;
if allocation(list) > 0 then if list = '(' then
do; out = list || out; free written, list; end;
if allocation (list) = 0 then leave translation;
if written then go to next_list;
written = true;
out = list || out; /* Output an operator. */
end;
put skip edit ('INPUT=' || s) (a); call show_stack;
put edit (' OUTPUT=', out) (col(30), 2 a);
end;
put skip list ('ALGEBRAIC EXPRESSION=', out);
end cvt;

View file

@ -0,0 +1,23 @@
my @tests = '3 4 2 * 1 5 - 2 3 ^ ^ / +',
'1 2 + 3 4 + ^ 5 6 + ^';
say rpm-to-infix($_) for @tests;
sub p ($pair, $prec) {
$pair.key < $prec ?? "( $pair.value() )" !! $pair.value
}
sub rpm-to-infix($string) {
say "=================\n$string";
my @stack;
for $string.words {
when /\d/ { @stack.push: 9 => $_ }
my $y = @stack.pop;
my $x = @stack.pop;
when '^' { @stack.push: 4 => ~(p($x,5), $_, p($y,4)) }
when '*' | '/' { @stack.push: 3 => ~(p($x,3), $_, p($y,3)) }
when '+' | '-' { @stack.push: 2 => ~(p($x,2), $_, p($y,2)) }
LEAVE { say @stack }
}
say "-----------------";
@stack».value;
}

View file

@ -0,0 +1,14 @@
# RPN to infix conversion
#
# Nigel Galloway April 1st., 2012
#
$WSb = '(?:^|\s+)';
$WSa = '(?:\s+|$)';
$num = '([+-/$]?(?:\.\d+|\d+(?:\.\d*)?))';
$op = '([-+*/^])';
while (<>) {
$n = -1;
while (s/$WSb$num\s+$num\s+$op$WSa/' '.('$'.++$n).' '/e) {@elems[$n] = '('.$1.$3.$2.')';}
while (s!(\$)(\d+)!@elems[$2]!e) {}
print(substr($_,2,-2)."\n");
}

View file

@ -0,0 +1,33 @@
(de leftAssoc (Op)
(member Op '("*" "/" "+" "-")) )
(de precedence (Op)
(case Op
("\^" 4)
(("*" "/") 3)
(("+" "-") 2) ) )
(de rpnToInfix (Str)
(let Stack NIL
(prinl "Token Stack")
(for Token (str Str "_")
(cond
((num? Token) (push 'Stack (cons 9 @))) # Highest precedence
((not (cdr Stack)) (quit "Stack empty"))
(T
(let (X (pop 'Stack) P (precedence Token))
(set Stack
(cons P
(pack
(if ((if (leftAssoc Token) < <=) (caar Stack) P)
(pack "(" (cdar Stack) ")")
(cdar Stack) )
" " Token " "
(if ((if (leftAssoc Token) <= <) (car X) P)
(pack "(" (cdr X) ")")
(cdr X) ) ) ) ) ) ) )
(prin Token)
(space 6)
(println Stack) )
(prog1 (cdr (pop 'Stack))
(and Stack (quit "Garbage remained on stack")) ) ) )

View file

@ -0,0 +1,31 @@
: (rpnToInfix "3 4 2 * 1 5 - 2 3 \^ \^ / +")
Token Stack
3 ((9 . 3))
4 ((9 . 4) (9 . 3))
2 ((9 . 2) (9 . 4) (9 . 3))
* ((3 . "4 * 2") (9 . 3))
1 ((9 . 1) (3 . "4 * 2") (9 . 3))
5 ((9 . 5) (9 . 1) (3 . "4 * 2") (9 . 3))
- ((2 . "1 - 5") (3 . "4 * 2") (9 . 3))
2 ((9 . 2) (2 . "1 - 5") (3 . "4 * 2") (9 . 3))
3 ((9 . 3) (9 . 2) (2 . "1 - 5") (3 . "4 * 2") (9 . 3))
^ ((4 . "2 \^ 3") (2 . "1 - 5") (3 . "4 * 2") (9 . 3))
^ ((4 . "(1 - 5) \^ 2 \^ 3") (3 . "4 * 2") (9 . 3))
/ ((3 . "4 * 2 / (1 - 5) \^ 2 \^ 3") (9 . 3))
+ ((2 . "3 + 4 * 2 / (1 - 5) \^ 2 \^ 3"))
-> "3 + 4 * 2 / (1 - 5) \^ 2 \^ 3"
: (rpnToInfix "1 2 + 3 4 + \^ 5 6 + \^")
Token Stack
1 ((9 . 1))
2 ((9 . 2) (9 . 1))
+ ((2 . "1 + 2"))
3 ((9 . 3) (2 . "1 + 2"))
4 ((9 . 4) (9 . 3) (2 . "1 + 2"))
+ ((2 . "3 + 4") (2 . "1 + 2"))
^ ((4 . "(1 + 2) \^ (3 + 4)"))
5 ((9 . 5) (4 . "(1 + 2) \^ (3 + 4)"))
6 ((9 . 6) (9 . 5) (4 . "(1 + 2) \^ (3 + 4)"))
+ ((2 . "5 + 6") (4 . "(1 + 2) \^ (3 + 4)"))
^ ((4 . "((1 + 2) \^ (3 + 4)) \^ (5 + 6)"))
-> "((1 + 2) \^ (3 + 4)) \^ (5 + 6)"

View file

@ -0,0 +1,223 @@
from math import log as ln
from math import sqrt, log, exp, sin, cos, tan, pi, e
"""
>>> # EXAMPLE USAGE
>>> result = rpn_to_infix('3 4 2 * 1 -5 - ln 2 3 ** ** / +', VERBOSE=True)
TOKEN STACK
3 ['3']
4 ['3', '4']
2 ['3', '4', '2']
* ['3', Node('2','*','4')]
1 ['3', Node('2','*','4'), '1']
-5 ['3', Node('2','*','4'), '1', '-5']
- ['3', Node('2','*','4'), Node('-5','-','1')]
ln ['3', Node('2','*','4'), Node(Node('-5','-','1'),'ln',None)]
2 ['3', Node('2','*','4'), Node(Node('-5','-','1'),'ln',None), '2']
3 ['3', Node('2','*','4'), Node(Node('-5','-','1'),'ln',None), '2', '3']
** ['3', Node('2','*','4'), Node(Node('-5','-','1'),'ln',None), Node('3','**','2')]
** ['3', Node('2','*','4'), Node(Node('3','**','2'),'**',Node(Node('-5','-','1'),'ln',None))]
/ ['3', Node(Node(Node('3','**','2'),'**',Node(Node('-5','-','1'),'ln',None)),'/',Node('2','*','4'))]
+ [Node(Node(Node(Node('3','**','2'),'**',Node(Node('-5','-','1'),'ln',None)),'/',Node('2','*','4')),'+','3')]
>>> result
"""
prec_dict = {'abs':5, 'sqrt':5, 'exp':5, 'log':5, 'ln':5,
'sin':5, 'cos':5, 'tan':5,
'**':4, '*':3, '/':3, '+':2, '-':2}
assoc_dict = {'abs':0, 'sqrt':0, 'exp':0, 'log':0, 'ln':0,
'sin':0, 'cos':0, 'tan':0,
'**':1, '*':0, '/':0, '+':0, '-':0}
arity_dict = {'abs':1, 'sqrt':1, 'exp':1, 'log':1, 'ln':1,
'sin':1, 'cos':1, 'tan':1,
'**':2, '*':2, '/':2, '+':2, '-':2}
class Node:
def __init__(self,x,op,y=None):
global prec_dict,assoc_dict,arity_dict
self.precedence = prec_dict[op]
self.assocright = assoc_dict[op]
self.arity = arity_dict[op]
self.op = op
if not self.assocright and self > x and \
isinstance(x, Node) and self.arity == 2:
self.x = x.x
self.y = Node(x.y, x.op, y)
else:
self.x,self.y = x,y
def __str__(self):
"""
Building an infix string that evaluates correctly is easy.
Building an infix string that looks pretty and evaluates
correctly requires more effort.
"""
# easy case, Node is unary
if self.y == None:
return '%s(%s)'%(self.op,str(self.x))
# determine left side string
str_y = str(self.y)
if self.y < self or \
(self.y == self and self.assocright) or \
(str_y[0] is '-' and self.assocright):
str_y = '(%s)'%str_y
# determine right side string and operator
str_x = str(self.x)
str_op = self.op
if self.op is '+' and not isinstance(self.x, Node) and str_x[0] is '-':
str_x = str_x[1:]
str_op = '-'
elif self.op is '-' and not isinstance(self.x, Node) and str_x[0] is '-':
str_x = str_x[1:]
str_op = '+'
elif self.x < self or \
(self.x == self and not self.assocright and \
getattr(self.x, 'op', 1) != getattr(self, 'op', 2)):
str_x = '(%s)'%str_x
return ' '.join([str_y, str_op, str_x])
def __repr__(self):
"""
>>> repr(Node('3','+','4')) == repr(eval(repr(Node('3','+','4'))))
True
"""
return 'Node(%s,%s,%s)'%(repr(self.x), repr(self.op), repr(self.y))
def __cmp__(self, other):
"""
polymorphic comparisons to determine precedence
>>> Node('3','+','4') < Node('6','*','7') < Node('3','**','4')
True
>>> Node('3','+','4') == Node('6','+','7')
True
>>> Node('3','+','4') == '-'
True
>>> Node('3','**','4') < '1'
True
"""
if isinstance(other, Node):
return cmp(self.precedence, other.precedence)
return cmp(self.precedence, prec_dict.get(other,9))
def rpn_to_infix(s, VERBOSE=False):
"""
converts rpn notation to infix notation for string s
"^" are replaced with "**"
>>> rpn_to_infix('5 4 +')
'5 + 4'
>>> rpn_to_infix('5 -4 +')
'5 - 4'
>>> rpn_to_infix('5 -4 -')
'5 + 4'
>>> rpn_to_infix('5 -4.2 +')
'5 - 4.2'
>>> rpn_to_infix('-4 2 **')
'(-4) ** 2'
>>> rpn_to_infix('x y +')
'x + y'
>>> rpn_to_infix('x -y +')
'x - y'
>>> rpn_to_infix('5 4 3 2 ** ** **')
'5 ** 4 ** 3 ** 2'
>>> rpn_to_infix('5 6 ** 7 **')
'(5 ** 6) ** 7'
>>> rpn_to_infix('1 2 3 + -')
'1 - (2 + 3)'
>>> rpn_to_infix('4 3 2 + +')
'4 + 3 + 2'
>>> rpn_to_infix('5 4 3 2 + + +')
'5 + 4 + 3 + 2'
>>> rpn_to_infix('5 4 3 2 * * *')
'5 * 4 * 3 * 2'
>>> rpn_to_infix('5 4 3 2 + - +')
'5 + (4 - (3 + 2))'
>>> rpn_to_infix('3 4 5 * -')
'3 - 4 * 5'
>>> rpn_to_infix('3 4 5 - *')
'(3 - 4) * 5'
>>> rpn_to_infix('4 2 * 1 5 - +')
'4 * 2 + (1 - 5)'
>>> rpn_to_infix('4 2 * 1 5 - 2 ** /')
'4 * 2 / (1 - 5) ** 2'
>>> rpn_to_infix('3 4 2 * 1 5 - 2 3 ** ** / +')
'3 + 4 * 2 / (1 - 5) ** 2 ** 3'
>>> rpn_to_infix('1 2 + 3 4 + ** 5 6 + **')
'((1 + 2) ** (3 + 4)) ** (5 + 6)'
>>> rpn_to_infix('x sin')
'sin(x)'
>>> rpn_to_infix('5 4 3 2 + sqrt - +')
'5 + (4 - sqrt(3 + 2))'
>>> rpn_to_infix('5 4 3 2 + sqrt ln - +')
'5 + (4 - ln(sqrt(3 + 2)))'
>>> rpn_to_infix('5 sin 4 cos *')
'sin(5) * cos(4)'
>>> rpn_to_infix('5 4 cos * sin')
'sin(5 * cos(4))'
>>> rpn_to_infix('3 4 2 * 1 -5 - ln 2 3 ** ** / +')
'3 + 4 * 2 / ln(1 + 5) ** 2 ** 3'
"""
global prec_dict, arity_dict
if VERBOSE : print('TOKEN STACK')
stack=[]
for token in s.replace('^','**').split():
if token in prec_dict:
if arity_dict[token] == 1:
stack.append(Node(stack.pop(),token))
elif arity_dict[token] == 2:
stack.append(Node(stack.pop(),token,stack.pop()))
else:
stack.append(token)
# can't use \t in order to make global docstring pass doctest
if VERBOSE : print(token+' '*(7-len(token))+repr(stack))
return str(stack[0])
def rpn_eval(s):
"""
computes the value of an rpn string
>>> rpn_eval('5 4 +') == eval(rpn_to_infix('5 4 +'))
True
>>> rpn_eval('-4 2 **') == eval(rpn_to_infix('-4 2 **'))
True
>>> round(rpn_eval('3 4 2 * 1 -5 - ln 2 3 ** ** / +'),7) == \
round(eval(rpn_to_infix('3 4 2 * 1 -5 - ln 2 3 ** ** / +')),7)
True
>>> round(rpn_eval('5 4 3 2 + sqrt ln - +'),7) == \
round(eval(rpn_to_infix('5 4 3 2 + sqrt ln - +')),7)
True
"""
global prec_dict, arity_dict
stack=[]
for token in s.replace('^','**').split():
if token in prec_dict:
if arity_dict[token] == 1:
stack.append(eval('%s(%s)'%(token,stack.pop())))
elif arity_dict[token] == 2:
x,y=stack.pop(),stack.pop()
stack.append(eval('(%s) %s %s'%(y,token,x)))
else:
stack.append(token)
return stack[0]
if __name__ == "__main__":
import doctest
doctest.testmod()

View file

@ -0,0 +1,36 @@
/*REXX program converts Reverse Polish Notation (RPN) ──► infix notation*/
showAction = 1 /* 0 if no showActions wanted. */
# = 0 /*initialize stack pointer to 0. */
oS = '+ - / * ^' /*operator symbols. */
oP = '2 2 3 3 4' /*operator priorities. */
oA = ' ' /*operator associations. */
say "infix: " toInfix( "3 4 2 * 1 5 - 2 3 ^ ^ / +" )
say "infix: " toInfix( "1 2 + 3 4 + ^ 5 6 + ^" ) /* [↓] Deutsch.*/
say "infix: " toInfix( "Mond Sterne Schlamm + * Feur Suppe * ^" )
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────────────────────────────────────────*/
pop: pop=#; #=#-1; return @.pop
push: #=#+1; @.#=arg(1); return
/*──────────────────────────────────────────────────────────────────────*/
stack2str: $=; do j=1 for #; _ = @.j; y=left(_,1)
if pos(' ',_)==0 then _ = '{'strip(substr(_,2))"}"
else _ = substr(_,2)
$=$ '{'strip(y _)"}"
end /*j*/
return space($)
/*──────────────────────────────────────────────────────────────────────*/
toInfix: parse arg rpn; say copies('',80-1); say 'RPN: ' space(rpn)
do N=1 to words(RPN); ?=word(RPN,N) /*process each of the RPN tokens.*/
if pos(?,oS)==0 then call push '¥' ? /*when in doubt, add a Yen to it.*/
else do; g=pop(); gp=left(g,1); g=substr(g,2)
h=pop(); hp=left(h,1); h=substr(h,2)
tp=substr(oP,pos(?,oS),1);ta=substr(oA,pos(?,oS),1)
if hp<tp | (hp==tp & ta=='') then h="("h")"
if gp<tp | (gp==tp & ta=='') then g="("g")"
call push tp || h ? g
end
if showAction then say right(?,25) "──►" stack2str()
end
return space(substr(pop(),2))

View file

@ -0,0 +1,3 @@
rpn = RPNExpression.new("3 4 2 * 1 5 - 2 3 ^ ^ / +")
infix = rpn.to_infix
ruby = rpn.to_ruby

View file

@ -0,0 +1,39 @@
package require Tcl 8.5
# Helpers
proc precassoc op {
dict get {^ {4 right} * {3 left} / {3 left} + {2 left} - {2 left}} $op
}
proc pop stk {
upvar 1 $stk s
set val [lindex $s end]
set s [lreplace $s end end]
return $val
}
proc rpn2infix rpn {
foreach token $rpn {
switch $token {
"^" - "/" - "*" - "+" - "-" {
lassign [pop stack] bprec b
lassign [pop stack] aprec a
lassign [precassoc $token] p assoc
if {$aprec < $p || ($aprec == $p && $assoc eq "right")} {
set a "($a)"
}
if {$bprec < $p || ($bprec == $p && $assoc eq "left")} {
set b "($b)"
}
lappend stack [list $p "$a $token $b"]
}
default {
lappend stack [list 9 $token]
}
}
puts "$token -> $stack"
}
return [lindex $stack end 1]
}
puts [rpn2infix {3 4 2 * 1 5 - 2 3 ^ ^ / +}]
puts [rpn2infix {1 2 + 3 4 + ^ 5 6 + ^}]