Streamlined looping
This commit is contained in:
@@ -65,6 +65,15 @@ enum TokenType {
|
||||
case MULTIPLICATION
|
||||
case DIVISION
|
||||
|
||||
case LOGICAL_AND
|
||||
case LOGICAL_OR
|
||||
case EQUAL
|
||||
case NOT_EQUAL
|
||||
case LESS_THAN
|
||||
case LESS_THAN_OR_EQUAL_TO
|
||||
case GREATER_THAN
|
||||
case GREATER_THAN_OR_EQUAL_TO
|
||||
|
||||
case UNDEFINED
|
||||
}
|
||||
|
||||
@@ -76,6 +85,7 @@ struct Token {
|
||||
typealias Construct = [Element]
|
||||
|
||||
enum Element {
|
||||
case Loop(type: ConstructType)
|
||||
case Construct(type: ConstructType)
|
||||
case Token(type: TokenType)
|
||||
}
|
||||
@@ -86,6 +96,14 @@ enum ConstructVariant {
|
||||
case Multiplication
|
||||
case Division
|
||||
|
||||
case LessThan
|
||||
case LessThanOrEqualTo
|
||||
case GreaterThan
|
||||
case GreaterThanOrEqualTo
|
||||
|
||||
case EqualTo
|
||||
case NotEqualTo
|
||||
|
||||
// Unary operation variants
|
||||
case Negation
|
||||
case BitwiseCompliment
|
||||
@@ -118,14 +136,22 @@ enum ConstructVariant {
|
||||
|
||||
enum ConstructType {
|
||||
case UnaryOperator
|
||||
|
||||
case MultiplicationPriorityOperator
|
||||
case AdditionPriorityOperator
|
||||
case Expression
|
||||
case Factor
|
||||
case Term
|
||||
case Statement
|
||||
case Function
|
||||
case InequalityPriorityOperator
|
||||
case EqualityPriorityOperator
|
||||
|
||||
case Program
|
||||
case Function
|
||||
case Statement
|
||||
case Expression
|
||||
case LogicalAndExpression
|
||||
case EqualityExpression
|
||||
case RelationalExpression
|
||||
case AdditiveExpression
|
||||
case Term
|
||||
case Factor
|
||||
}
|
||||
|
||||
struct ConstructDefinitions {
|
||||
@@ -164,17 +190,41 @@ let constructDefinitions: Dictionary<ConstructType, Dictionary<ConstructVariant,
|
||||
],
|
||||
],
|
||||
|
||||
.InequalityPriorityOperator: [
|
||||
.LessThan: [
|
||||
.Token(type: .LESS_THAN),
|
||||
],
|
||||
.LessThanOrEqualTo: [
|
||||
.Token(type: .LESS_THAN_OR_EQUAL_TO),
|
||||
],
|
||||
.GreaterThan: [
|
||||
.Token(type: .GREATER_THAN),
|
||||
],
|
||||
.GreaterThanOrEqualTo: [
|
||||
.Token(type: .GREATER_THAN_OR_EQUAL_TO),
|
||||
],
|
||||
],
|
||||
|
||||
.EqualityPriorityOperator: [
|
||||
.EqualTo: [
|
||||
.Token(type: .EQUAL),
|
||||
],
|
||||
.NotEqualTo: [
|
||||
.Token(type: .NOT_EQUAL),
|
||||
],
|
||||
],
|
||||
|
||||
.Expression: [
|
||||
.TermSequence: [
|
||||
.Construct(type: .Term),
|
||||
.Construct(type: .AdditionPriorityOperator),
|
||||
.Loop(type: .AdditionPriorityOperator),
|
||||
]
|
||||
],
|
||||
|
||||
.Term: [
|
||||
.FactorSequence: [
|
||||
.Construct(type: .Factor),
|
||||
.Construct(type: .MultiplicationPriorityOperator),
|
||||
.Loop(type: .MultiplicationPriorityOperator),
|
||||
]
|
||||
],
|
||||
|
||||
@@ -336,6 +386,14 @@ func lex(string: String) -> [Substring] {
|
||||
line = line.replacing("+", with: " + ")
|
||||
line = line.replacing("*", with: " * ")
|
||||
line = line.replacing("/", with: " / ")
|
||||
line = line.replacing("&&", with: " && ")
|
||||
line = line.replacing("||", with: " || ")
|
||||
line = line.replacing("==", with: " == ")
|
||||
line = line.replacing("!=", with: " != ")
|
||||
line = line.replacing("<", with: " < ")
|
||||
line = line.replacing("<=", with: " <= ")
|
||||
line = line.replacing(">", with: " > ")
|
||||
line = line.replacing(">=", with: " >= ")
|
||||
|
||||
do {
|
||||
let tokens: [Substring] = line.split(separator: try Regex(" +"))
|
||||
@@ -519,7 +577,7 @@ func parse(lexed: [Substring]) -> String {
|
||||
|
||||
let abstractSyntaxTree = SyntaxTreeNode(.Root)
|
||||
|
||||
if validateConstruct(program.variants[.SingleFunction]!, tokens: &tokens, node: abstractSyntaxTree, loopingEnabled: false) != .Invalid {
|
||||
if validateConstruct(type: .Program, variant: .SingleFunction, tokens: &tokens, node: abstractSyntaxTree) != .Invalid {
|
||||
print("Success")
|
||||
print(abstractSyntaxTree.text())
|
||||
print("Assembly:")
|
||||
@@ -539,7 +597,7 @@ enum Validity {
|
||||
case Break
|
||||
}
|
||||
|
||||
func validateConstruct(_ construct: Construct, tokens: inout [Token], node: SyntaxTreeNode, loopingEnabled: Bool) -> Validity {
|
||||
func validateConstruct(type: ConstructType, variant: ConstructVariant, tokens: inout [Token], node: SyntaxTreeNode) -> Validity {
|
||||
var indent: String {
|
||||
var count: Int = 0
|
||||
var child: SyntaxTreeNode = node
|
||||
@@ -550,10 +608,119 @@ func validateConstruct(_ construct: Construct, tokens: inout [Token], node: Synt
|
||||
return String(repeating: " ", count: count)
|
||||
}
|
||||
|
||||
var loop: Bool = loopingEnabled
|
||||
var loop: Bool = false
|
||||
repeat {
|
||||
let construct = constructDefinitions[type]![variant]!
|
||||
for element in construct {
|
||||
switch element {
|
||||
case .Loop(let constructType):
|
||||
/*
|
||||
var matchingOperator: Bool = false
|
||||
|
||||
print("\(indent)Determining need for loop")
|
||||
let tokenBackup: [Token] = tokens
|
||||
for constructVariant in constructDefinitions[constructType]!.keys {
|
||||
let childNode = node.addChild(value: variant)
|
||||
print("\(indent)Testing operator \(constructType)::\(constructVariant)")
|
||||
let valid = validateConstruct(type: constructType, variant: constructVariant, tokens: &tokens, node: node)
|
||||
if valid == .Panic {
|
||||
return .Invalid
|
||||
} else if valid == .Invalid {
|
||||
tokens = tokenBackup
|
||||
_ = node.popLastChild()
|
||||
continue
|
||||
}
|
||||
matchingOperator = true
|
||||
break
|
||||
}
|
||||
|
||||
loop = matchingOperator
|
||||
if loop {
|
||||
print("\(indent)Looping")
|
||||
} else {
|
||||
print("\(indent)Not looping")
|
||||
return .Valid
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var valid: Validity = .Invalid
|
||||
var matchingOperator: Bool = false
|
||||
print("\(indent)Determining need to loop construct of type \(constructType)")
|
||||
let tokenBackup: [Token] = tokens
|
||||
for constructVariant in constructDefinitions[constructType]!.keys {
|
||||
let childNode = node.addChild(value: constructVariant)
|
||||
print("\(indent)Testing operator \(constructType)::\(constructVariant)")
|
||||
|
||||
valid = validateConstruct(type: constructType, variant: constructVariant, tokens: &tokens, node: childNode)
|
||||
if valid == .Panic {
|
||||
print("\(indent)Fail: panic (variant \"\(constructVariant)\"))\n")
|
||||
return .Invalid
|
||||
} else if valid == .Invalid {
|
||||
tokens = tokenBackup
|
||||
_ = node.popLastChild()
|
||||
continue
|
||||
}
|
||||
matchingOperator = true
|
||||
break
|
||||
}
|
||||
|
||||
loop = matchingOperator
|
||||
|
||||
if loop {
|
||||
print("\(indent)Looping")
|
||||
} else {
|
||||
print("\(indent)Not looping")
|
||||
break
|
||||
}
|
||||
|
||||
/*
|
||||
if valid == .Invalid {
|
||||
print("\(indent)Subconstruct validation failed")
|
||||
return .Invalid
|
||||
} else if valid == .Break {
|
||||
print("\(indent)End validate subconstruct (variant \"\(validVariant) by breaking\")")
|
||||
break
|
||||
}
|
||||
*/
|
||||
|
||||
//print("\(indent)End validate subconstruct (variant \"\(validVariant)\")")
|
||||
break
|
||||
|
||||
case .Token(let type):
|
||||
if let token: Token = tokens.popLast() {
|
||||
if type != token.type {
|
||||
print("\(indent)VALIDATION FAILED FOR TOKEN \"\(token.content)\"")
|
||||
return .Invalid
|
||||
}
|
||||
print("\(indent)Validated token \"\(token.content)\"")
|
||||
|
||||
if token.type == .LITERAL_INTEGER {
|
||||
node.value = String(token.content)
|
||||
}
|
||||
else if token.type == .IDENTIFIER {
|
||||
node.value = String(token.content)
|
||||
}
|
||||
|
||||
continue
|
||||
|
||||
} else {
|
||||
print("\(indent)RAN OUT OF TOKENS")
|
||||
return .Invalid
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
break
|
||||
|
||||
case .Construct(let type):
|
||||
print("\(indent)Begin validate subconstruct (type \"\(type)\")")
|
||||
|
||||
@@ -568,7 +735,7 @@ func validateConstruct(_ construct: Construct, tokens: inout [Token], node: Synt
|
||||
}
|
||||
|
||||
print("\(indent)Testing variant \(variant) (Loop = \(loop)) (Loopable = \(loopable))")
|
||||
valid = validateConstruct(constructDefinitions[type]![variant]!, tokens: &tokens, node: childNode, loopingEnabled: loopable)
|
||||
valid = validateConstruct(type: type, variant: variant, tokens: &tokens, node: childNode)
|
||||
if valid == .Panic {
|
||||
print("\(indent)Fail: panic (variant \"\(variant)\"))\n")
|
||||
return .Invalid
|
||||
@@ -587,38 +754,6 @@ func validateConstruct(_ construct: Construct, tokens: inout [Token], node: Synt
|
||||
|
||||
|
||||
|
||||
if loopingEnabled {
|
||||
// Factor looping nonsense
|
||||
if type == .Factor {
|
||||
let nextToken: Token = tokens[tokens.count - 1]
|
||||
if nextToken.type == .MULTIPLICATION || nextToken.type == .DIVISION {
|
||||
print("\(indent)Looping due to factor")
|
||||
loop = true
|
||||
} else {
|
||||
if node.children.count != 0 {
|
||||
print("\(indent)Breaking out of factor loop")
|
||||
loop = false
|
||||
return .Break
|
||||
} else {
|
||||
print("\(indent)ERROR: FactorSequence has no children")
|
||||
return .Panic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Term looping nonsense
|
||||
else if type == .Term {
|
||||
let nextToken: Token = tokens[tokens.count - 1]
|
||||
if nextToken.type == .ADDITION || nextToken.type == .NEGATION {
|
||||
print("\(indent)Looping due to term")
|
||||
loop = true
|
||||
} else {
|
||||
print("\(indent)Breaking out of term loop")
|
||||
loop = false
|
||||
return .Break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -678,6 +813,14 @@ func categorizeToken(token: Substring) -> TokenType {
|
||||
else if token.firstMatch(of: /^\+$/) != nil { return .ADDITION }
|
||||
else if token.firstMatch(of: /^\*$/) != nil { return .MULTIPLICATION }
|
||||
else if token.firstMatch(of: /^\/$/) != nil { return .DIVISION }
|
||||
else if token.firstMatch(of: /^&&$/) != nil { return .LOGICAL_AND }
|
||||
else if token.firstMatch(of: /^||$/) != nil { return .LOGICAL_OR }
|
||||
else if token.firstMatch(of: /^==$/) != nil { return .EQUAL }
|
||||
else if token.firstMatch(of: /^!=$/) != nil { return .NOT_EQUAL }
|
||||
else if token.firstMatch(of: /^<$/) != nil { return .LESS_THAN }
|
||||
else if token.firstMatch(of: /^<=$/) != nil { return .LESS_THAN_OR_EQUAL_TO }
|
||||
else if token.firstMatch(of: /^>$/) != nil { return .GREATER_THAN }
|
||||
else if token.firstMatch(of: /^>=$/) != nil { return .GREATER_THAN_OR_EQUAL_TO }
|
||||
|
||||
return .UNDEFINED
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user