Blood, sweat, and tears... And it's only stage 3

This commit is contained in:
2026-01-29 21:51:43 -05:00
parent 39d4a12d2c
commit cde395a2a9

View File

@@ -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 {