Add tasks for all the new languages
This commit is contained in:
parent
9dc3c2bb62
commit
bba7bfd280
13208 changed files with 134745 additions and 0 deletions
|
|
@ -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``");
|
||||
}
|
||||
|
|
@ -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)))
|
||||
|
|
@ -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 ^ /")
|
||||
|
|
@ -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(' ');
|
||||
|
|
@ -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)")
|
||||
Loading…
Add table
Add a link
Reference in a new issue