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