Blood, sweat, and tears... And it's only stage 3
This commit is contained in:
@@ -92,12 +92,10 @@ enum ConstructVariant {
|
||||
case LogicalNegation
|
||||
|
||||
// Expression variants
|
||||
case AdditionPriorityOperation
|
||||
case SingleTerm
|
||||
case TermSequence
|
||||
|
||||
// Term variants
|
||||
case MultiplicationPriorityOperation
|
||||
case SingleFactor
|
||||
case FactorSequence
|
||||
|
||||
// Factor variants
|
||||
case LiteralInteger
|
||||
@@ -167,24 +165,16 @@ let constructDefinitions: Dictionary<ConstructType, Dictionary<ConstructVariant,
|
||||
],
|
||||
|
||||
.Expression: [
|
||||
.AdditionPriorityOperation: [
|
||||
.Construct(type: .Expression),
|
||||
.TermSequence: [
|
||||
.Construct(type: .Term),
|
||||
.Construct(type: .AdditionPriorityOperator),
|
||||
.Construct(type: .Term)
|
||||
],
|
||||
.SingleTerm: [
|
||||
.Construct(type: .Term)
|
||||
]
|
||||
],
|
||||
|
||||
.Term: [
|
||||
.MultiplicationPriorityOperation: [
|
||||
.Construct(type: .Term),
|
||||
.FactorSequence: [
|
||||
.Construct(type: .Factor),
|
||||
.Construct(type: .MultiplicationPriorityOperator),
|
||||
.Construct(type: .Term)
|
||||
],
|
||||
.SingleFactor: [
|
||||
.Construct(type: .Factor)
|
||||
]
|
||||
],
|
||||
|
||||
@@ -302,7 +292,7 @@ func getTestFiles() -> [TestFile] {
|
||||
var testFiles: [TestFile] = [TestFile]()
|
||||
|
||||
let fileManager = FileManager.default
|
||||
let path = "c/tests/stage_2"
|
||||
let path = "c/tests/stage_3"
|
||||
|
||||
do {
|
||||
let validItems = try fileManager.contentsOfDirectory(atPath: path + "/valid")
|
||||
@@ -343,6 +333,9 @@ 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: " / ")
|
||||
|
||||
do {
|
||||
let tokens: [Substring] = line.split(separator: try Regex(" +"))
|
||||
@@ -365,7 +358,7 @@ func parse(lexed: [Substring]) -> String {
|
||||
|
||||
let abstractSyntaxTree = SyntaxTreeNode(.Root)
|
||||
|
||||
if validateConstruct(program.variants[.SingleFunction]!, tokens: &tokens, node: abstractSyntaxTree) {
|
||||
if validateConstruct(program.variants[.SingleFunction]!, tokens: &tokens, node: abstractSyntaxTree) != .Invalid {
|
||||
print("Success")
|
||||
print(abstractSyntaxTree.text())
|
||||
print("Assembly:")
|
||||
@@ -387,6 +380,18 @@ func generateOutput(_ node: SyntaxTreeNode) -> String {
|
||||
}
|
||||
break
|
||||
|
||||
case .TermSequence:
|
||||
for child in node.children {
|
||||
text += generateOutput(child)
|
||||
}
|
||||
break
|
||||
|
||||
case .FactorSequence:
|
||||
for child in node.children {
|
||||
text += generateOutput(child)
|
||||
}
|
||||
break
|
||||
|
||||
case .Integer:
|
||||
text += " .globl \(node.value)\n\(node.value):\n"
|
||||
for child in node.children {
|
||||
@@ -439,61 +444,111 @@ func generateOutput(_ node: SyntaxTreeNode) -> String {
|
||||
return text
|
||||
}
|
||||
|
||||
func validateConstruct(_ construct: Construct, tokens: inout [Token], node: SyntaxTreeNode) -> Bool {
|
||||
for element in construct {
|
||||
switch element {
|
||||
case .Construct(let type):
|
||||
print("Begin validate subconstruct (type \"\(type)\")")
|
||||
enum Validity {
|
||||
case Valid
|
||||
case Invalid
|
||||
case Break
|
||||
}
|
||||
|
||||
var valid: Bool = false
|
||||
var validVariant: ConstructVariant = .Error
|
||||
let tokenBackup: [Token] = tokens
|
||||
for key in constructDefinitions[type]!.keys {
|
||||
let childNode = node.addChild(value: key)
|
||||
print("Testing variant \(key)")
|
||||
if !validateConstruct(constructDefinitions[type]![key]!, tokens: &tokens, node: childNode) {
|
||||
print("Fail")
|
||||
tokens = tokenBackup
|
||||
_ = node.popLastChild()
|
||||
continue
|
||||
}
|
||||
print("Success")
|
||||
valid = true
|
||||
validVariant = key
|
||||
break
|
||||
}
|
||||
if !valid {
|
||||
print("Subconstruct validation failed")
|
||||
return false
|
||||
}
|
||||
print("End validate subconstruct (variant \"\(validVariant)\")")
|
||||
continue
|
||||
func validateConstruct(_ construct: Construct, tokens: inout [Token], node: SyntaxTreeNode) -> Validity {
|
||||
var loop: Bool = false
|
||||
repeat {
|
||||
for element in construct {
|
||||
switch element {
|
||||
case .Construct(let type):
|
||||
print("Begin validate subconstruct (type \"\(type)\")")
|
||||
|
||||
case .Token(let type):
|
||||
if let token: Token = tokens.popLast() {
|
||||
if type != token.type {
|
||||
print("VALIDATION FAILED FOR TOKEN \"\(token.content)\"")
|
||||
return false
|
||||
}
|
||||
print("Validated token \"\(token.content)\"")
|
||||
var valid: Validity = .Invalid
|
||||
var validVariant: ConstructVariant = .Error
|
||||
let tokenBackup: [Token] = tokens
|
||||
for key in constructDefinitions[type]!.keys {
|
||||
let childNode = node.addChild(value: key)
|
||||
print("Testing variant \(key) (Loop = \(loop))")
|
||||
valid = validateConstruct(constructDefinitions[type]![key]!, tokens: &tokens, node: childNode)
|
||||
if valid == .Invalid {
|
||||
print("Fail")
|
||||
tokens = tokenBackup
|
||||
_ = node.popLastChild()
|
||||
continue
|
||||
}
|
||||
print("Success")
|
||||
validVariant = key
|
||||
|
||||
if token.type == .LITERAL_INTEGER {
|
||||
node.value = String(token.content)
|
||||
break
|
||||
}
|
||||
else if token.type == .IDENTIFIER {
|
||||
node.value = String(token.content)
|
||||
|
||||
|
||||
|
||||
|
||||
// Factor looping nonsense
|
||||
if type == .Factor {
|
||||
let nextToken: Token = tokens[tokens.count - 1]
|
||||
if nextToken.type == .MULTIPLICATION || nextToken.type == .DIVISION {
|
||||
print("Looping due to factor")
|
||||
loop = true
|
||||
} else {
|
||||
print("Breaking out of factor loop")
|
||||
loop = false
|
||||
return .Break
|
||||
}
|
||||
}
|
||||
|
||||
// Term looping nonsense
|
||||
else if type == .Term {
|
||||
let nextToken: Token = tokens[tokens.count - 1]
|
||||
if nextToken.type == .ADDITION || nextToken.type == .NEGATION {
|
||||
print("Looping due to term")
|
||||
loop = true
|
||||
} else {
|
||||
print("Breaking out of term loop")
|
||||
loop = false
|
||||
return .Break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if valid == .Invalid {
|
||||
print("Subconstruct validation failed")
|
||||
return .Invalid
|
||||
} else if valid == .Break {
|
||||
print("End validate subconstruct (variant \"\(validVariant) by breaking\")")
|
||||
print(type)
|
||||
break
|
||||
}
|
||||
|
||||
print("End validate subconstruct (variant \"\(validVariant)\")")
|
||||
print(type)
|
||||
|
||||
continue
|
||||
|
||||
} else {
|
||||
print("RAN OUT OF TOKENS")
|
||||
return false
|
||||
case .Token(let type):
|
||||
if let token: Token = tokens.popLast() {
|
||||
if type != token.type {
|
||||
print("VALIDATION FAILED FOR TOKEN \"\(token.content)\"")
|
||||
return .Invalid
|
||||
}
|
||||
print("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("RAN OUT OF TOKENS")
|
||||
return .Invalid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while loop
|
||||
|
||||
return true
|
||||
return .Valid
|
||||
}
|
||||
|
||||
func categorizeToken(token: Substring) -> TokenType {
|
||||
|
||||
Reference in New Issue
Block a user