Just another update
This commit is contained in:
parent
a25938f123
commit
00a190b0a6
6591 changed files with 94363 additions and 23227 deletions
|
|
@ -15,13 +15,13 @@ isOp _ = False
|
|||
simSYA xs = final ++ [lastStep]
|
||||
where final = scanl f ([],[],"") xs
|
||||
lastStep = (\(x,y,_) -> (reverse y ++ x, [], "")) $ last final
|
||||
f (out,st,_) t | isOp t =
|
||||
f (out,st,_) t | isOp t =
|
||||
(reverse (takeWhile testOp st) ++ out
|
||||
, (t:) $ (dropWhile testOp st), t)
|
||||
| t == "(" = (out, "(":st, t)
|
||||
| t == ")" = (reverse (takeWhile (/="(") st) ++ out,
|
||||
| t == "(" = (out, "(":st, t)
|
||||
| t == ")" = (reverse (takeWhile (/="(") st) ++ out,
|
||||
tail $ dropWhile (/="(") st, t)
|
||||
| True = (t:out, st, t)
|
||||
| otherwise = (t:out, st, t)
|
||||
where testOp x = isOp x && (leftAssoc t && prec t == prec x
|
||||
|| prec t < prec x)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
{-# LANGUAGE LambdaCase #-}
|
||||
import Control.Applicative
|
||||
import Control.Lens
|
||||
import Control.Monad
|
||||
import Control.Monad.Error
|
||||
import Control.Monad.State
|
||||
import System.Console.Readline
|
||||
|
|
@ -60,13 +61,11 @@ pushVal n = _1 %= (OutVal n:)
|
|||
pushParen :: RPNComp ()
|
||||
pushParen = _2 %= (Paren:)
|
||||
|
||||
--Run StateT. `process` is effectively foldM_ with the base case to
|
||||
--format the output string
|
||||
--Run StateT
|
||||
toRPN :: [InToken] -> Either String [OutToken]
|
||||
toRPN xs = evalStateT (process (return ()) xs) ([],[])
|
||||
where process st [] = st >> get >>= \(a,b) -> (reverse a++) <$>
|
||||
(mapM toOut b)
|
||||
process st (x:xs) = process (st >> processToken x) xs
|
||||
toRPN xs = evalStateT process ([],[])
|
||||
where process = mapM_ processToken xs
|
||||
>> get >>= \(a,b) -> (reverse a++) <$> (mapM toOut b)
|
||||
toOut :: StackElem -> RPNComp OutToken
|
||||
toOut (StOp o) = return $ OutOp o
|
||||
toOut Paren = throwError "Unmatched left parenthesis"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
import java.util.Stack;
|
||||
|
||||
public class ShuntingYard {
|
||||
|
||||
public static void main(String[] args) {
|
||||
String infix = "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3";
|
||||
System.out.printf("infix: %s%n", infix);
|
||||
System.out.printf("postfix: %s%n", infixToPostfix(infix));
|
||||
}
|
||||
|
||||
static String infixToPostfix(String infix) {
|
||||
final String ops = "-+/*^";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Stack<Integer> s = new Stack<>();
|
||||
|
||||
for (String token : infix.split("\\s")) {
|
||||
char c = token.charAt(0);
|
||||
int idx = ops.indexOf(c);
|
||||
if (idx != -1 && token.length() == 1) {
|
||||
if (s.isEmpty())
|
||||
s.push(idx);
|
||||
else {
|
||||
while (!s.isEmpty()) {
|
||||
int prec2 = s.peek() / 2;
|
||||
int prec1 = idx / 2;
|
||||
if (prec2 > prec1 || (prec2 == prec1 && c != '^'))
|
||||
sb.append(ops.charAt(s.pop())).append(' ');
|
||||
else break;
|
||||
}
|
||||
s.push(idx);
|
||||
}
|
||||
} else if (c == '(') {
|
||||
s.push(-2);
|
||||
} else if (c == ')') {
|
||||
while (s.peek() != -2)
|
||||
sb.append(ops.charAt(s.pop())).append(' ');
|
||||
s.pop();
|
||||
} else {
|
||||
sb.append(token).append(' ');
|
||||
}
|
||||
}
|
||||
while (!s.isEmpty())
|
||||
sb.append(ops.charAt(s.pop())).append(' ');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
function Stack() {
|
||||
this.dataStore = [];
|
||||
this.top = 0;
|
||||
this.push = push;
|
||||
this.pop = pop;
|
||||
this.peek = peek;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
function push(element) {
|
||||
this.dataStore[this.top++] = element;
|
||||
}
|
||||
|
||||
function pop() {
|
||||
return this.dataStore[--this.top];
|
||||
}
|
||||
|
||||
function peek() {
|
||||
return this.dataStore[this.top-1];
|
||||
}
|
||||
|
||||
function length() {
|
||||
return this.top;
|
||||
}
|
||||
|
||||
var infix = "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3";
|
||||
infix = infix.replace(/\s+/g, ''); // remove spaces, so infix[i]!=" "
|
||||
|
||||
var s = new Stack();
|
||||
var ops = "-+/*^";
|
||||
var precedence = {"^":4, "*":3, "/":3, "+":2, "-":2};
|
||||
var associativity = {"^":"Right", "*":"Left", "/":"Left", "+":"Left", "-":"Left"};
|
||||
var token;
|
||||
var postfix = "";
|
||||
var o1, o2;
|
||||
|
||||
for (var i = 0; i < infix.length; i++) {
|
||||
token = infix[i];
|
||||
if (token > "0" && token < "9") { // if token is operand (here limited to 0 <= x <= 9)
|
||||
postfix += token + " ";
|
||||
}
|
||||
else if (ops.indexOf(token) != -1) { // if token is an operator
|
||||
o1 = token;
|
||||
o2 = s.peek();
|
||||
while (ops.indexOf(o2)!=-1 && ( // while operator token, o2, on top of the stack
|
||||
// and o1 is left-associative and its precedence is less than or equal to that of o2
|
||||
(associativity[o1] == "Left" && (precedence[o1] <= precedence[o2]) ) ||
|
||||
// the algorithm on wikipedia says: or o1 precedence < o2 precedence, but I think it should be
|
||||
// or o1 is right-associative and its precedence is less than that of o2
|
||||
(associativity[o1] == "Right" && (precedence[o1] < precedence[o2]))
|
||||
)){
|
||||
postfix += o2 + " "; // add o2 to output queue
|
||||
s.pop(); // pop o2 of the stack
|
||||
o2 = s.peek(); // next round
|
||||
}
|
||||
s.push(o1); // push o1 onto the stack
|
||||
}
|
||||
else if (token == "(") { // if token is left parenthesis
|
||||
s.push(token); // then push it onto the stack
|
||||
}
|
||||
else if (token == ")") { // if token is right parenthesis
|
||||
while (s.peek() != "("){ // until token at top is (
|
||||
postfix += s.pop() + " ";
|
||||
}
|
||||
s.pop(); // pop (, but not onto the output queue
|
||||
}
|
||||
}
|
||||
while (s.length()>0){
|
||||
postfix += s.pop() + " ";
|
||||
}
|
||||
print(postfix);
|
||||
|
|
@ -1,51 +1,49 @@
|
|||
use 5.010;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my %prec = (
|
||||
'^' => 4,
|
||||
'*' => 3,
|
||||
'/' => 3,
|
||||
'+' => 2,
|
||||
'-' => 2,
|
||||
'(' => 1);
|
||||
'^' => 4,
|
||||
'*' => 3,
|
||||
'/' => 3,
|
||||
'+' => 2,
|
||||
'-' => 2,
|
||||
'(' => 1
|
||||
);
|
||||
|
||||
my %assoc = (
|
||||
'^' => 'right',
|
||||
'*' => 'left',
|
||||
'/' => 'left',
|
||||
'+' => 'left',
|
||||
'-' => 'left');
|
||||
'^' => 'right',
|
||||
'*' => 'left',
|
||||
'/' => 'left',
|
||||
'+' => 'left',
|
||||
'-' => 'left'
|
||||
);
|
||||
|
||||
sub shunting_yard {
|
||||
my @inp = split ' ', $_[0];
|
||||
my @ops;
|
||||
my @res;
|
||||
my @inp = split ' ', $_[0];
|
||||
my @ops;
|
||||
my @res;
|
||||
|
||||
my $report = sub { printf "%25s %-7s %10s %s\n", "@res", "@ops", $_[0], "@inp" };
|
||||
my $shift = sub { $report->( "shift @_"); push @ops, @_ };
|
||||
my $reduce = sub { $report->("reduce @_"); push @res, @_ };
|
||||
my $report = sub { printf "%25s %-7s %10s %s\n", "@res", "@ops", $_[0], "@inp" };
|
||||
my $shift = sub { $report->("shift @_"); push @ops, @_ };
|
||||
my $reduce = sub { $report->("reduce @_"); push @res, @_ };
|
||||
|
||||
while( @inp ) {
|
||||
given( shift @inp ) {
|
||||
when ( /\d/ ) { $reduce->($_) }
|
||||
when ( '(' ) { $shift->($_) }
|
||||
when ( ')' ) { while( @ops and "(" ne (my $x = pop @ops) ) { $reduce->( $x ) } }
|
||||
default {
|
||||
my $newprec = $prec{$_};
|
||||
while( @ops ) {
|
||||
my $oldprec = $prec{$ops[-1]};
|
||||
last if $newprec > $oldprec;
|
||||
last if $newprec == $oldprec and $assoc{$_} eq 'right';
|
||||
$reduce->( pop @ops );
|
||||
}
|
||||
$shift->( $_ );
|
||||
}
|
||||
}
|
||||
}
|
||||
while (@inp) {
|
||||
my $token = shift @inp;
|
||||
if ( $token =~ /\d/ ) { $reduce->($token) }
|
||||
elsif ( $token eq '(' ) { $shift->($token) }
|
||||
elsif ( $token eq ')' ) {
|
||||
while ( @ops and "(" ne ( my $x = pop @ops ) ) { $reduce->($x) }
|
||||
} else {
|
||||
my $newprec = $prec{$token};
|
||||
while (@ops) {
|
||||
my $oldprec = $prec{ $ops[-1] };
|
||||
last if $newprec > $oldprec;
|
||||
last if $newprec == $oldprec and $assoc{$token} eq 'right';
|
||||
$reduce->( pop @ops );
|
||||
}
|
||||
$shift->($token);
|
||||
}
|
||||
}
|
||||
$reduce->( pop @ops ) while @ops;
|
||||
@res;
|
||||
}
|
||||
|
||||
local $, = " ";
|
||||
say shunting_yard '3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3' ;
|
||||
print shunting_yard '3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
Option Explicit
|
||||
Option Base 1
|
||||
|
||||
Function ShuntingYard(strInfix As String) As String
|
||||
Dim i As Long, j As Long, token As String, tokenArray() As String
|
||||
Dim stack() As Variant, queue() As Variant, discard As String
|
||||
Dim op1 As String, op2 As String
|
||||
|
||||
Debug.Print strInfix
|
||||
|
||||
' Get tokens
|
||||
tokenArray = Split(strInfix)
|
||||
|
||||
' Initialize array (removed later)
|
||||
ReDim stack(1)
|
||||
ReDim queue(1)
|
||||
|
||||
' Loop over tokens
|
||||
Do While 1
|
||||
i = i + 1
|
||||
If i - 1 > UBound(tokenArray) Then
|
||||
Exit Do
|
||||
Else
|
||||
token = tokenArray(i - 1) 'i-1 due to Split returning a Base 0
|
||||
End If
|
||||
If token = "" Then: Exit Do
|
||||
|
||||
' Print
|
||||
Debug.Print i, token, Join(stack, ","), Join(queue, ",")
|
||||
' If-loop over tokens (either brackets, operators, or numbers)
|
||||
If token = "(" Then
|
||||
stack = push(token, stack)
|
||||
ElseIf token = ")" Then
|
||||
While Peek(stack) <> "("
|
||||
queue = push(pop(stack), queue)
|
||||
Wend
|
||||
discard = pop(stack) 'discard "("
|
||||
ElseIf isOperator(token) Then
|
||||
op1 = token
|
||||
Do While (isOperator(Peek(stack)))
|
||||
' Debug.Print Peek(stack)
|
||||
op2 = Peek(stack)
|
||||
If op2 <> "^" And precedence(op1) = precedence(op2) Then
|
||||
'"^" is the only right-associative operator
|
||||
queue = push(pop(stack), queue)
|
||||
ElseIf precedence(op1$) < precedence(op2$) Then
|
||||
queue = push(pop(stack), queue)
|
||||
Else
|
||||
Exit Do
|
||||
End If
|
||||
Loop
|
||||
stack = push(op1, stack)
|
||||
Else 'number
|
||||
'actually, wrong operator could end up here, like say %
|
||||
'If the token is a number, then add it to the output queue.
|
||||
queue = push(CStr(token), queue)
|
||||
End If
|
||||
Loop
|
||||
|
||||
While stack(1) <> ""
|
||||
If Peek(stack) = "(" Then Debug.Print "no matching ')'": End
|
||||
queue = push(pop(stack), queue)
|
||||
Wend
|
||||
|
||||
' Print final output
|
||||
ShuntingYard = Join(queue, " ")
|
||||
Debug.Print "Output:"
|
||||
Debug.Print ShuntingYard
|
||||
End Function
|
||||
|
||||
'------------------------------------------
|
||||
Function isOperator(op As String) As Boolean
|
||||
isOperator = InStr("+-*/^", op) <> 0 And Len(op$) = 1
|
||||
End Function
|
||||
|
||||
Function precedence(op As String) As Integer
|
||||
If isOperator(op$) Then
|
||||
precedence = 1 _
|
||||
- (InStr("+-*/^", op$) <> 0) _
|
||||
- (InStr("*/^", op$) <> 0) _
|
||||
- (InStr("^", op$) <> 0)
|
||||
End If
|
||||
End Function
|
||||
|
||||
'------------------------------------------
|
||||
Function push(str, stack) As Variant
|
||||
Dim out() As Variant, i As Long
|
||||
If Not IsEmpty(stack(1)) Then
|
||||
out = stack
|
||||
ReDim Preserve out(1 To UBound(stack) + 1)
|
||||
out(UBound(out)) = str
|
||||
Else
|
||||
ReDim out(1 To 1)
|
||||
out(1) = str
|
||||
End If
|
||||
push = out
|
||||
End Function
|
||||
|
||||
Function pop(stack)
|
||||
pop = stack(UBound(stack))
|
||||
If UBound(stack) > 1 Then
|
||||
ReDim Preserve stack(1 To UBound(stack) - 1)
|
||||
Else
|
||||
stack(1) = ""
|
||||
End If
|
||||
End Function
|
||||
|
||||
Function Peek(stack)
|
||||
Peek = stack(UBound(stack))
|
||||
End Function
|
||||
Loading…
Add table
Add a link
Reference in a new issue