Skip to content

Instantly share code, notes, and snippets.

@zoren
Created April 19, 2016 13:15
Show Gist options
  • Save zoren/a44f6a6c15962e6975744d2e6b155658 to your computer and use it in GitHub Desktop.
Save zoren/a44f6a6c15962e6975744d2e6b155658 to your computer and use it in GitHub Desktop.
A implementation of the Operator precedence parser from Wikipedia in Swift 2
// Created by Søren Sjørup on 16/04/16.
// Copyright © 2016 Søren Sjørup. All rights reserved.
import Foundation
indirect enum Exp{
case C(Int)
case Bin(Exp, String, Exp)
}
indirect enum S{
case Primary(Exp)
case Operator(String)
}
enum Errors :ErrorType {
case ExpectedPrimExpAtIndex(Int)
case ExpectedOperatorAtIndex(Int)
case ExpectedExpFoundEOF
}
func parseExp(prec:[String:Int], _ s:[S]) throws -> Exp {
var index = 0
func parsePrim() throws -> Exp {
if index >= s.count{
throw Errors.ExpectedExpFoundEOF
}
switch s[index] {
case .Primary(let e):
index += 1
return e
case .Operator(_):
throw Errors.ExpectedPrimExpAtIndex(index)
}
}
func peekNextOperator() throws -> String {
let i = index
if i >= s.count{
return ""
}
switch s[i] {
case .Primary(_):
throw Errors.ExpectedOperatorAtIndex(i)
case .Operator(let opString):
return opString
}
}
func parseExp1(inout lhs:Exp, minPrec:Int) throws -> Exp{
var lookahead = try peekNextOperator()
while prec[lookahead] >= minPrec {
let op = lookahead
index += 1
var rhs = try parsePrim()
lookahead = try peekNextOperator()
while prec[lookahead] > prec[op] {
rhs = try parseExp1(&rhs, minPrec: prec[lookahead]!)
lookahead = try peekNextOperator()
}
lhs = .Bin(lhs, op, rhs)
}
return lhs
}
var pp = try parsePrim()
return try parseExp1(&pp, minPrec: 0)
}
// testing
let prec : [String:Int] = ["+":140, "%":150, "*":150]
let stream : [S] =
[.Primary(.C(2)), .Operator("+"), .Primary(.C(3)), .Operator("%"), .Primary(.C(4)), .Operator("*"), .Primary(.C(5))]
let v = try parseExp(prec, stream)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment