Add tasks for all the new languages

This commit is contained in:
Tina Müller 2016-12-05 23:44:36 +01:00
parent 9dc3c2bb62
commit bba7bfd280
13208 changed files with 134745 additions and 0 deletions

View file

@ -0,0 +1,106 @@
import ceylon.collection {
ArrayList
}
abstract class Token(String|Integer data) of IntegerLiteral | Operator | leftParen | rightParen {
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 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``");
}

View file

@ -0,0 +1,52 @@
(require 'hash)
(require 'tree)
(define OPS (make-hash))
(hash-set OPS "^" '( 4 #f)) ;; right assoc
(hash-set OPS "*" '( 3 #t)) ;; left assoc
(hash-set OPS "/" '( 3 #t))
(hash-set OPS "+" '( 2 #t))
(hash-set OPS "-" '( 2 #t))
;; helpers
(define (is-right-par? token) (string=? token ")"))
(define (is-left-par? token) (string=? token "("))
(define (is-num? op) (not (hash-ref OPS op))) ;; crude
(define (is-op? op) (hash-ref OPS op))
(define (is-left? op) (second (hash-ref OPS op)))
(define (is-right? op) (not (is-left? op)))
(define (op-prec op) (first (hash-ref OPS op)))
;; Wikipedia algorithm, translated as it is
(define (shunt tokens S Q)
(for ((token tokens))
(writeln "S: " (stack->list S) "Q: " (queue->list Q) "token: "token)
(cond
[(is-left-par? token) (push S token) ]
[(is-right-par? token)
(while (and (stack-top S) (not (is-left-par? (stack-top S))))
(q-push Q ( pop S)))
(when (stack-empty? S) (error 'misplaced-parenthesis "()" ))
(pop S)] ; // left par
[(is-op? token)
(while (and
(is-op? (stack-top S))
(or
(and (is-left? token) (<= (op-prec token) (op-prec (stack-top S))))
(and (is-right? token) (< (op-prec token) (op-prec (stack-top S))))))
(q-push Q (pop S)))
(push S token)]
[(is-num? token) (q-push Q token)]
[else (error 'bad-token token)])) ; for
(while (stack-top S) (q-push Q (pop S))))
(string-delimiter "")
(define (task infix)
(define S (stack 'S))
(define Q (queue 'Q))
(shunt (text-parse infix) S Q)
(writeln 'infix infix)
(writeln 'RPN (queue->list Q)))

View file

@ -0,0 +1,82 @@
integer show_workings = 1
constant operators = {"^","*","/","+","-"},
precedence = { 4, 3, 3, 2, 2 }
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)
printf(1,"Infix input: %-30s%s", {infix,iff(show_workings?'\n':'\t')})
for i=1 to length(ops) do
string op = ops[i]
if op="(" then
stack = append(stack,op)
elsif op=")" then
while 1 do
top = stack[$]
stack = stack[1..$-1]
if top="(" then exit end if
res &= sep&top
sep = " "
end while
else
integer k = find(op,operators)
if k!=0 then
integer prec = precedence[k]
while length(stack) do
top = stack[$]
k = find(top,operators)
if k=0 or prec>precedence[k]
or (top="^" and prec=precedence[k]) then
exit
end if
stack = stack[1..$-1]
res &= sep&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
shunting_yard("3 + 4 * 2 / (1 - 5) ^ 2 ^ 3","3 4 2 * 1 5 - 2 3 ^ ^ / +")
show_workings = 0
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 ^ /")

View file

@ -0,0 +1,50 @@
var prec = Hash(
'^' => 4,
'*' => 3,
'/' => 3,
'+' => 2,
'-' => 2,
'(' => 1,
);
var assoc = Hash(
'^' => 'right',
'*' => 'left',
'/' => 'left',
'+' => 'left',
'-' => 'left',
);
func shunting_yard(prog) {
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 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) } }
default {
var newprec = prec{t};
while (ops) {
var oldprec = prec{ops[-1]};
break if (newprec > oldprec)
break if ((newprec == oldprec) && (assoc{t} == 'right'))
reduce(ops.pop);
}
shift(t);
}
}
}
while (ops) { reduce(ops.pop) }
return res
}
say shunting_yard('3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3').join(' ');

View file

@ -0,0 +1,175 @@
import Foundation
// Using arrays for both stack and queue
struct Stack<T> {
private(set) var elements = [T]()
var isEmpty: Bool { return elements.isEmpty }
mutating func push(newElement: T) {
elements.append(newElement)
}
mutating func pop() -> T {
return elements.removeLast()
}
func top() -> T? {
return elements.last
}
}
struct Queue<T> {
private(set) var elements = [T]()
var isEmpty: Bool { return elements.isEmpty }
mutating func enqueue(newElement: T) {
elements.append(newElement)
}
mutating func dequeue() -> T {
return elements.removeFirst()
}
}
enum Associativity { case Left, Right }
// Define abstract interface, which can be used to restrict Set extension
protocol OperatorType: Comparable, Hashable {
var name: String { get }
var precedence: Int { get }
var associativity: Associativity { get }
}
struct Operator: OperatorType {
let name: String
let precedence: Int
let associativity: Associativity
// same operator names are not allowed
var hashValue: Int { return "\(name)".hashValue }
init(_ name: String, _ precedence: Int, _ associativity: Associativity) {
self.name = name; self.precedence = precedence; self.associativity = associativity
}
}
func ==(x: Operator, y: Operator) -> Bool {
// same operator names are not allowed
return x.name == y.name
}
func <(x: Operator, y: Operator) -> Bool {
// compare operators by their precedence and associavity
return (x.associativity == .Left && x.precedence == y.precedence) || x.precedence < y.precedence
}
extension Set where Element: OperatorType {
func contains(op: String?) -> Bool {
guard let operatorName = op else { return false }
return contains { $0.name == operatorName }
}
subscript (operatorName: String) -> Element? {
get {
return filter { $0.name == operatorName }.first
}
}
}
// Convenience
extension String {
var isNumber: Bool { return Double(self) != nil }
}
struct ShuntingYard {
enum Error: ErrorType {
case MismatchedParenthesis(String)
case UnrecognizedToken(String)
}
static func parse(input: String, operators: Set<Operator>) throws -> String {
var stack = Stack<String>()
var output = Queue<String>()
let tokens = input.componentsSeparatedByString(" ")
for token in tokens {
// Wikipedia: if token is a number add it to the output queue
if token.isNumber {
output.enqueue(token)
}
// Wikipedia: else if token is a operator:
else if operators.contains(token) {
// Wikipedia: while there is a operator on top of the stack and has lower precedence than current operator (token)
while operators.contains(stack.top()) && hasLowerPrecedence(token, stack.top()!, operators) {
// Wikipedia: pop it off to the output queue
output.enqueue(stack.pop())
}
// Wikipedia: push current operator (token) onto the operator stack
stack.push(token)
}
// Wikipedia: If the token is a left parenthesis, then push it onto the stack.
else if token == "(" {
stack.push(token)
}
// Wikipedia: If the token is a right parenthesis:
else if token == ")" {
// Wikipedia: Until the token at the top of the stack is a left parenthesis
while !stack.isEmpty && stack.top() != "(" {
// Wikipedia: pop operators off the stack onto the output queue.
output.enqueue(stack.pop())
}
// If the stack runs out, than there are mismatched parentheses.
if stack.isEmpty {
throw Error.MismatchedParenthesis(input)
}
// Wikipedia: Pop the left parenthesis from the stack, but not onto the output queue.
stack.pop()
}
// if token is not number, operator or a parenthesis, then is not recognized
else {
throw Error.UnrecognizedToken(token)
}
}
// Wikipedia: When there are no more tokens to read:
// Wikipedia: While there are still operator tokens in the stack:
while operators.contains(stack.top()) {
// Wikipedia: Pop the operator onto the output queue.
output.enqueue(stack.pop())
}
// Wikipedia: If the operator token on the top of the stack is a parenthesis, then there are mismatched parentheses
// Note: Assume that all operators has been poped onto the output queue.
if stack.isEmpty == false {
throw Error.MismatchedParenthesis(input)
}
return output.elements.joinWithSeparator(" ")
}
static private func containsOperator(stack: Stack<String>, _ operators: [String: NSDictionary]) -> Bool {
guard stack.isEmpty == false else { return false }
// Is there a matching operator in the operators set?
return operators[stack.top()!] != nil ? true : false
}
static private func hasLowerPrecedence(x: String, _ y: String, _ operators: Set<Operator>) -> Bool {
guard let first = operators[x], let second = operators[y] else { return false }
return first < second
}
}
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)
print("input: \(input)")
print("output: \(output)")