September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -0,0 +1,78 @@
BEGIN
# parses s and returns an RPN expression using Dijkstra's "Shunting Yard" algorithm #
# s is expected to contain a valid infix expression containing single-digit numbers and single-character operators #
PROC parse = ( STRING s )STRING:
BEGIN
# add to the output #
PROC output element = ( CHAR c )VOID:
BEGIN
output[ output pos +:= 1 ] := c;
output pos +:= 1
END # output element # ;
PROC stack op = ( CHAR c )VOID: stack[ stack pos +:= 1 ] := c;
# unstacks and returns the top operator on the stack - stops the program if the stack is empty #
PROC unstack = CHAR:
IF stack pos < 1 THEN
# empty stack #
print( ( "Stack underflow", newline ) );
stop
ELSE
# still something on the stack to unstack #
CHAR result = stack[ stack pos ];
stack[ stack pos ] := " ";
stack pos -:= 1;
result
FI # unstack # ;
# returns the priority of the operator o - which must be one of "(", "^", "*", "/", "+" or "-" #
PROC priority of = ( CHAR o )INT: IF o = "(" THEN -1 ELIF o = "^" THEN 4 ELIF o = "*" OR o = "/" THEN 3 ELSE 2 FI;
# returns TRUE if o is a right-associative operator, FALSE otherwise #
PROC right = ( CHAR c )BOOL: c = "^";
PROC lower or equal priority = ( CHAR c )BOOL:
IF stack pos < 1 THEN FALSE # empty stack #
ELSE priority of( c ) <= priority of( stack[ stack pos ] )
FI # lower or equal priority # ;
PROC lower priority = ( CHAR c )BOOL:
IF stack pos < 1 THEN FALSE # empty stack #
ELSE priority of( c ) < priority of( stack[ stack pos ] )
FI # lower priority # ;
# max stack size and output size #
INT max stack = 32;
# stack and output queue #
[ 1 : max stack ]CHAR stack;
[ 1 : max stack ]CHAR output;
FOR c pos TO max stack DO stack[ c pos ] := output[ c pos ] := " " OD;
# stack pointer and output queue pointer #
INT stack pos := 0;
INT output pos := 0;
print( ( "Parsing: ", s, newline ) );
print( ( "token output stack", newline ) );
FOR s pos FROM LWB s TO UPB s DO
CHAR c = s[ s pos ];
IF c /= " " THEN
IF c >= "0" AND c <= "9" THEN output element( c )
ELIF c = "(" THEN stack op( c )
ELIF c = ")" THEN
# close bracket - unstack to the matching "(" and unstack the "(" #
WHILE CHAR op char = unstack;
op char /= "("
DO
output element( op char )
OD
ELIF right( c ) THEN
# right associative operator #
WHILE lower priority( c ) DO output element( unstack ) OD;
stack op( c )
ELSE
# must be left associative #
WHILE lower or equal priority( c ) DO output element( unstack ) OD;
stack op( c )
FI;
print( ( c, " ", output, " ", stack, newline ) )
FI
OD;
WHILE stack pos >= 1 DO output element( unstack ) OD;
output[ 1 : output pos ]
END # parse # ;
print( ( "result: ", parse( "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3" ), newline ) )
END

View file

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main() {
string infix = "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3";
Console.WriteLine(infix.ToPostfix());
}
}
public static class ShuntingYard
{
private static readonly Dictionary<string, (string symbol, int precedence, bool rightAssociative)> operators
= new (string symbol, int precedence, bool rightAssociative) [] {
("^", 4, true),
("*", 3, false),
("/", 3, false),
("+", 2, false),
("-", 2, false)
}.ToDictionary(op => op.symbol);
public static string ToPostfix(this string infix) {
string[] tokens = infix.Split(' ');
var stack = new Stack<string>();
var output = new List<string>();
foreach (string token in tokens) {
if (int.TryParse(token, out _)) {
output.Add(token);
Print(token);
} else if (operators.TryGetValue(token, out var op1)) {
while (stack.Count > 0 && operators.TryGetValue(stack.Peek(), out var op2)) {
int c = op1.precedence.CompareTo(op2.precedence);
if (c < 0 || !op1.rightAssociative && c <= 0) {
output.Add(stack.Pop());
} else {
break;
}
}
stack.Push(token);
Print(token);
} else if (token == "(") {
stack.Push(token);
Print(token);
} else if (token == ")") {
string top = "";
while (stack.Count > 0 && (top = stack.Pop()) != "(") {
output.Add(top);
}
if (top != "(") throw new ArgumentException("No matching left parenthesis.");
Print(token);
}
}
while (stack.Count > 0) {
var top = stack.Pop();
if (!operators.ContainsKey(top)) throw new ArgumentException("No matching right parenthesis.");
output.Add(top);
}
Print("pop");
return string.Join(" ", output);
//Yikes!
void Print(string action) => Console.WriteLine($"{action + ":",-4} {$"stack[ {string.Join(" ", stack.Reverse())} ]",-18} {$"out[ {string.Join(" ", output)} ]"}");
//A little more readable?
void Print(string action) => Console.WriteLine("{0,-4} {1,-18} {2}", action + ":", $"stack[ {string.Join(" ", stack.Reverse())} ]", $"out[ {string.Join(" ", output)} ]");
}
}

View file

@ -9,7 +9,11 @@ public class ShuntingYard {
}
static String infixToPostfix(String infix) {
/* To find out the precedence, we take the index of the
token in the ops string and divide by 2 (rounding down).
This will give us: 0, 0, 1, 1, 2 */
final String ops = "-+/*^";
StringBuilder sb = new StringBuilder();
Stack<Integer> s = new Stack<>();

View file

@ -0,0 +1,59 @@
type associativity = Left | Right;;
let prec op =
match op with
| "^" -> 4
| "*" -> 3
| "/" -> 3
| "+" -> 2
| "-" -> 2
| _ -> -1;;
let assoc op =
match op with
| "^" -> Right
| _ -> Left;;
let split_while p =
let rec go ls xs =
match xs with
| x::xs' when p x -> go (x::ls) xs'
| _ -> List.rev ls, xs
in go [];;
let rec intercalate sep xs =
match xs with
| [] -> ""
| [x] -> x
| x::xs' -> x ^ sep ^ intercalate sep xs';;
let shunting_yard =
let rec pusher stack queue tkns =
match tkns with
| [] -> List.rev queue @ stack
| "("::tkns' -> pusher ("("::stack) queue tkns'
| ")"::tkns' ->
let mv, "("::stack' = split_while ((<>) "(") stack in
pusher stack' (mv @ queue) tkns'
| t::tkns' when prec t < 0 -> pusher stack (t::queue) tkns'
| op::tkns' ->
let mv_to_queue op2 =
(match assoc op with
| Left -> prec op <= prec op2
| Right -> prec op < prec op2)
in
let mv, stack' = split_while mv_to_queue stack in
pusher (op::stack') (mv @ queue) tkns'
in pusher [] [];;
let () =
let inp = read_line () in
let tkns = String.split_on_char ' ' inp in
let postfix = shunting_yard tkns in
print_endline (intercalate " " postfix);;

View file

@ -6,8 +6,7 @@ constant operators = {"^","*","/","+","-"},
procedure shunting_yard(string infix, string rpn)
string res = "", sep = "", top
sequence stack = {}
--sequence ops = split(infix) -- (only works if () properly spaced)
sequence ops = split(substitute_all(infix,{"(",")"},{" ( "," ) "}),' ',0,1)
sequence ops = split(substitute_all(infix,{"(",")"},{" ( "," ) "}),' ',no_empty:=1,limit:=0)
printf(1,"Infix input: %-30s%s", {infix,iff(show_workings?'\n':'\t')})
for i=1 to length(ops) do
string op = ops[i]

View file

@ -5,7 +5,7 @@ var prec = Hash(
'+' => 2,
'-' => 2,
'(' => 1,
);
)
var assoc = Hash(
'^' => 'right',
@ -13,38 +13,46 @@ var assoc = Hash(
'/' => 'left',
'+' => 'left',
'-' => 'left',
);
)
func shunting_yard(prog) {
var inp = prog.words;
var ops = [];
var res = [];
var inp = prog.words
var ops = []
var res = []
 
func report (op) {
printf("%25s  %-7s %10s %s\n",
res.join(' '), ops.join(' '), op, inp.join(' '))
}
func report (op) { printf("%25s %-7s %10s %s\n", res.join(' '), ops.join(' '), op, inp.join(' ')) }
func shift (t) { report( "shift #{t}"); ops << t }
func reduce (t) { report("reduce #{t}"); res << t }
 
while (inp) {
given(var t = inp.shift) {
when (/\d/) { reduce(t) }
when ('(') { shift(t) }
when (')') { var x; while (ops && (x = ops.pop) && (x != '(')) { reduce(x) } }
when (')') {
while (ops) {
(var x = ops.pop) == '(' ? break : reduce(x)
}
}
default {
var newprec = prec{t};
var newprec = prec{t}
while (ops) {
var oldprec = prec{ops[-1]};
var oldprec = prec{ops[-1]}
 
break if (newprec > oldprec)
break if ((newprec == oldprec) && (assoc{t} == 'right'))
reduce(ops.pop);
 
reduce(ops.pop)
}
shift(t);
shift(t)
}
}
}
while (ops) { reduce(ops.pop) }
return res
}
say shunting_yard('3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3').join(' ');
 
say shunting_yard('3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3').join(' ')

View file

@ -0,0 +1,170 @@
Function ShuntingYard(strInfix As String) As String
Dim i as Integer
Dim token, tokenArray() As String
Dim stack(), queue() As Variant
Dim discard As String
Dim op1, op2 As String
Dim Left_Brackets, Right_Brackets As Integer
Dim output As String
Dim dbl_output As Double
Left_Brackets = CountFields(strInfix, "(")
Right_Brackets = CountFields(strInfix, ")")
If Left_Brackets = Right_Brackets Then
'Get tokens
tokenArray = Split(strInfix," ")
'Initialize array (removed later)
ReDim stack(1)
ReDim queue(1)
'Loop over tokens
For i = 0 to tokenArray.Ubound
'i = i + 1
If i > UBound(tokenArray) Then
Exit For
Else
token = tokenArray(i ) 'i-1 due to Split returning a Base 0
End If
If token = "" Then
Exit For
End If
Dim stackString As String
Dim queuString As String
for m as Integer = 0 to stack.Ubound
stackString = stackString + " " + stack(m)
Next
for m as Integer = 0 to queue.Ubound
queuString = queuString + " " + queue(m)
Next
MsgBox(Str(i) + " " + token + " " + stackString + " " + queuString)
'Window1.txtQueu.Text = Window1.txtQueu.Text + Str(i) + " " + token + " " + stackString + " " + queuString + EndOfLIne
' If-loop over tokens (either brackets, operators, or numbers)
If token = "(" Then
stack.Append(token)
ElseIf token = ")" Then
While stack(stack.Ubound) <> "("
queue.Append(stack.pop)
Wend
discard = stack.Pop 'discard "("
ElseIf isOperator(token) Then
op1 = token
//Do While (isOperator(Peek(stack)))
While isOperator( stack(stack.Ubound) ) = True
op2 = stack(stack.Ubound)
If op2 <> "^" And precedence(op1) = precedence(op2) Then
'"^" is the only right-associative operator
queue.Append(stack.pop)
ElseIf precedence(op1) < precedence(op2) Then
queue.Append(stack.Pop)
Else
Exit While
End If
Wend
//Loop
stack.Append(op1)
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.Append(CStr(token))
End If
Next
for i = 0 to queue.Ubound
output = output +queue(i) + " "
next
for i = stack.Ubound DownTo 0
output = output + stack(i)+" "
next
While InStr(output, " ") <> 0
output = ReplaceAll(output," "," ")
Wend
output = Trim(output)
Return output
Else
MsgBox("Syntax Error!" + EndOfLine + "Count left brackets: " + Str(Left_Brackets) + EndOfLine +"Count right brackets: " + Str(Right_Brackets))
End If
End Function
Function isOperator(op As String) As Boolean
If InStr("+-*/^", op) <> 0 and Len(op) = 1 Then
Return True
End If
End Function
Function precedence(op As String) As Integer
If isOperator(op) = True Then
If op = "+" or op = "-" Then
Return 2
ElseIf op = "/" or op = "*" Then
Return 3
ElseIf op = "^" Then
Return 4
End If
End If
End Function

View file

@ -0,0 +1,51 @@
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),
);
"infix: ".println(input);
"postfix:".println(parseInfix(input));
fcn parseInfix(e){
stack:=List(); // holds operators and left parenthesis
rpn:="";
foreach tok in (e.split(" ")){
switch(tok){
case("("){ stack.append(tok) } // push "(" to stack
case(")"){
while(True){ // pop item ("(" or operator) from stack
op:=stack.pop();
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){
// consider top item on stack
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
}
} // switch
display(tok,rpn,stack);
} // foreach
// drain stack to result
rpn + stack.reverse().concat(" ");
}
fcn display(tok,rpn,stack){
"Token|".println(tok);
"Stack|".println(stack.concat());
"Queue|".println(rpn);
println();
}