From e08bb2ff95dc6a6b02562d8e633922316baea8aa Mon Sep 17 00:00:00 2001 From: Trevor Maze Date: Mon, 2 Feb 2026 20:57:00 -0500 Subject: [PATCH] Logical operators and equality/inequality operators --- Sources/rxcc/rxcc.swift | 232 +++++++++++++++++++++++++++++++--------- oldtest.c | 4 + test.c | 2 +- 3 files changed, 189 insertions(+), 49 deletions(-) create mode 100644 oldtest.c diff --git a/Sources/rxcc/rxcc.swift b/Sources/rxcc/rxcc.swift index 814bb0b..574b317 100644 --- a/Sources/rxcc/rxcc.swift +++ b/Sources/rxcc/rxcc.swift @@ -230,7 +230,7 @@ let constructDefinitions: Dictionary [TestFile] { var testFiles: [TestFile] = [TestFile]() let fileManager = FileManager.default - let path = "c/tests/stage_3" + let path = "c/tests/stage_4" do { let validItems = try fileManager.contentsOfDirectory(atPath: path + "/valid") @@ -438,14 +438,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: " <= ") - 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(" +")) @@ -474,26 +474,195 @@ func generateOutput(_ node: SyntaxTreeNode) -> String { break case .LogicalAndExpressionSequence: - for child in node.children { + var operation: ConstructVariant = .Error + let count = node.children.count + if count == 0 { + print("ERROR: \(node.variant) with no children") + break + } + for i in 0...count - 1 { + let child: SyntaxTreeNode = node.children[i] + let uuid: String = String(UUID().uuidString.split(separator: "-")[0]) + + // Operation + if i % 2 == 1 { + operation = child.variant + continue + } + text += generateOutput(child) + + switch operation { + case .LogicalOr: + text += " movl\t%eax, %ecx\n" // Put e2 in ecx + text += " pop \t%eax\n" // Put e1 in eax + text += " cmpl\t$0, %eax\n" + text += " je \tlabel_\(uuid)\n" + text += " movl\t$1, %eax\n" + text += " jmp \tend_\(uuid)\n" + text += "label_\(uuid):\n" + text += " movl\t%ecx, %eax\n" // Put e2 in eax + text += " cmpl\t$0, %eax\n" + text += " movl\t$0, %eax\n" + text += " setne\t%al\n" + text += "end_\(uuid):\n" + + default: + if i != 0 { + print("Unknown operation \"\(operation)\" in \(node.variant)") + } + break + } + + if i != node.children.count - 1 { + text += " push\t%eax\n" + } } break case .EqualityExpressionSequence: - for child in node.children { + var operation: ConstructVariant = .Error + let count = node.children.count + if count == 0 { + print("ERROR: \(node.variant) with no children") + break + } + for i in 0...count - 1 { + let child: SyntaxTreeNode = node.children[i] + let uuid: String = String(UUID().uuidString.split(separator: "-")[0]) + + // Operation + if i % 2 == 1 { + operation = child.variant + continue + } + text += generateOutput(child) + + switch operation { + case .LogicalAnd: + text += " movl\t%eax, %ecx\n" // Put e2 in ecx + text += " pop \t%eax\n" // Put e1 in eax + text += " cmpl\t$0, %eax\n" + text += " jne \tlabel_\(uuid)\n" + text += " jmp \tend_\(uuid)\n" + text += "label_\(uuid):\n" + text += " movl\t%ecx, %eax\n" // Put e2 in eax + text += " cmpl\t$0, %eax\n" + text += " movl\t$0, %eax\n" + text += " setne\t%al\n" + text += "end_\(uuid):\n" + + default: + if i != 0 { + print("Unknown operation \"\(operation)\" in \(node.variant)") + } + break + } + + if i != node.children.count - 1 { + text += " push\t%eax\n" + } } break case .RelationalExpressionSequence: - for child in node.children { + var operation: ConstructVariant = .Error + let count = node.children.count + if count == 0 { + print("ERROR: \(node.variant) with no children") + break + } + for i in 0...count - 1 { + let child: SyntaxTreeNode = node.children[i] + + // Operation + if i % 2 == 1 { + operation = child.variant + continue + } + text += generateOutput(child) + + switch operation { + case .EqualTo: + text += " pop \t%ecx\n" + text += " cmpl\t%eax, %ecx\n" + text += " movl\t$0, %eax\n" + text += " sete\t%al\n" + + case .NotEqualTo: + text += " pop \t%ecx\n" + text += " cmpl\t%eax, %ecx\n" + text += " movl\t$0, %eax\n" + text += " setne\t%al\n" + + default: + if i != 0 { + print("Unknown operation \"\(operation)\" in \(node.variant)") + } + break + } + + if i != node.children.count - 1 { + text += " push\t%eax\n" + } } break case .AdditiveExpressionSequence: - for child in node.children { + var operation: ConstructVariant = .Error + let count = node.children.count + if count == 0 { + print("ERROR: \(node.variant) with no children") + break + } + for i in 0...count - 1 { + let child: SyntaxTreeNode = node.children[i] + + // Operation + if i % 2 == 1 { + operation = child.variant + continue + } + text += generateOutput(child) + + switch operation { + case .LessThan: + text += " pop \t%ecx\n" + text += " cmpl\t%eax, %ecx\n" + text += " movl\t$0, %eax\n" + text += " setl\t%al\n" + + case .LessThanOrEqualTo: + text += " pop \t%ecx\n" + text += " cmpl\t%eax, %ecx\n" + text += " movl\t$0, %eax\n" + text += " setle\t%al\n" + + case .GreaterThan: + text += " pop \t%ecx\n" + text += " cmpl\t%eax, %ecx\n" + text += " movl\t$0, %eax\n" + text += " setg\t%al\n" + + case .GreaterThanOrEqualTo: + text += " pop \t%ecx\n" + text += " cmpl\t%eax, %ecx\n" + text += " movl\t$0, %eax\n" + text += " setge\t%al\n" + + default: + if i != 0 { + print("Unknown operation \"\(operation)\" in \(node.variant)") + } + break + } + + if i != node.children.count - 1 { + text += " push\t%eax\n" + } } break @@ -501,7 +670,7 @@ func generateOutput(_ node: SyntaxTreeNode) -> String { var operation: ConstructVariant = .Error let count = node.children.count if count == 0 { - print("ERROR: FactorSequence with no children") + print("ERROR: \(node.variant) with no children") break } for i in 0...count - 1 { @@ -527,7 +696,7 @@ func generateOutput(_ node: SyntaxTreeNode) -> String { default: if i != 0 { - print("Unknown operation \"\(operation)\" in FactorSequence") + print("Unknown operation \"\(operation)\" in \(node.variant)") } break } @@ -690,40 +859,6 @@ func validateConstruct(type: ConstructType, variant: ConstructVariant, tokens: i 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)") @@ -800,6 +935,7 @@ func validateConstruct(type: ConstructType, variant: ConstructVariant, tokens: i if let token: Token = tokens.popLast() { if type != token.type { print("\(indent)VALIDATION FAILED FOR TOKEN \"\(token.content)\"") + print("\(indent)AKA, \(type) not equal to \(token.type)") return .Invalid } print("\(indent)Validated token \"\(token.content)\"") @@ -841,7 +977,7 @@ func categorizeToken(token: Substring) -> TokenType { 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 .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 } diff --git a/oldtest.c b/oldtest.c new file mode 100644 index 0000000..30a9028 --- /dev/null +++ b/oldtest.c @@ -0,0 +1,4 @@ +int main() { + return !(4 + -4) + 6 / (2 + 2) * -4 * ~4 / 9 + -(4 / (5 * (32 / 2) + ~1) - (400 / 90 + 1) - -~((5 / 4) * (2 + 3) / -9)); +} + diff --git a/test.c b/test.c index 30a9028..b293070 100644 --- a/test.c +++ b/test.c @@ -1,4 +1,4 @@ int main() { - return !(4 + -4) + 6 / (2 + 2) * -4 * ~4 / 9 + -(4 / (5 * (32 / 2) + ~1) - (400 / 90 + 1) - -~((5 / 4) * (2 + 3) / -9)); + return 1 || 0 && 2; }