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