|
|
|
|
@@ -17,8 +17,6 @@ enum TokenType {
|
|
|
|
|
case UNDEFINED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let UNARY_OPERATORS: [TokenType] = [.NEGATION, .BITWISE_COMPLIMENT, .LOGICAL_NEGATION]
|
|
|
|
|
|
|
|
|
|
struct Token {
|
|
|
|
|
let content: Substring
|
|
|
|
|
let type: TokenType
|
|
|
|
|
@@ -28,7 +26,7 @@ typealias Construct = [Element]
|
|
|
|
|
|
|
|
|
|
enum Element {
|
|
|
|
|
case Construct(type: ConstructDefinitions);
|
|
|
|
|
case Token(types: [TokenType])
|
|
|
|
|
case Token(type: TokenType)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ConstructType {
|
|
|
|
|
@@ -38,20 +36,95 @@ enum ConstructType {
|
|
|
|
|
case Program
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ConstructVariant {
|
|
|
|
|
// Expression variants
|
|
|
|
|
case LiteralInteger
|
|
|
|
|
case Negation
|
|
|
|
|
case BitwiseCompliment
|
|
|
|
|
case LogicalNegation
|
|
|
|
|
|
|
|
|
|
// Statement variants
|
|
|
|
|
case ReturnInteger
|
|
|
|
|
|
|
|
|
|
// Function Variants
|
|
|
|
|
case Integer
|
|
|
|
|
|
|
|
|
|
// Program Variants
|
|
|
|
|
case SingleFunction
|
|
|
|
|
|
|
|
|
|
// Misc.
|
|
|
|
|
case Root
|
|
|
|
|
case Error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class SyntaxTreeNode {
|
|
|
|
|
var parent: SyntaxTreeNode?
|
|
|
|
|
var children: [SyntaxTreeNode]
|
|
|
|
|
|
|
|
|
|
var variant: ConstructVariant
|
|
|
|
|
var value: String
|
|
|
|
|
|
|
|
|
|
init(_ variant: ConstructVariant) {
|
|
|
|
|
self.parent = nil
|
|
|
|
|
self.children = [SyntaxTreeNode]()
|
|
|
|
|
self.variant = variant
|
|
|
|
|
self.value = ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init(_ variant: ConstructVariant, parent: SyntaxTreeNode) {
|
|
|
|
|
self.parent = parent
|
|
|
|
|
self.children = [SyntaxTreeNode]()
|
|
|
|
|
self.variant = variant
|
|
|
|
|
self.value = ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func addChild(value: ConstructVariant) -> SyntaxTreeNode {
|
|
|
|
|
let child = SyntaxTreeNode(value, parent: self)
|
|
|
|
|
children.append(child)
|
|
|
|
|
return child
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func popLastChild() -> SyntaxTreeNode {
|
|
|
|
|
if let last: SyntaxTreeNode = children.popLast() {
|
|
|
|
|
return last
|
|
|
|
|
}
|
|
|
|
|
return SyntaxTreeNode(.Error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func text(_ level: Int = 0) -> String {
|
|
|
|
|
var text: String = "\(variant)"
|
|
|
|
|
if variant == .LiteralInteger {
|
|
|
|
|
text += "(\(value))"
|
|
|
|
|
}
|
|
|
|
|
for child in children {
|
|
|
|
|
text += "\n\(String(repeating: " ", count: level))└───\(child.text(level + 1))"
|
|
|
|
|
}
|
|
|
|
|
return text
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ConstructDefinitions {
|
|
|
|
|
var type: ConstructType
|
|
|
|
|
var variants: Dictionary<String, Construct>
|
|
|
|
|
var variants: Dictionary<ConstructVariant, Construct>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let expression: ConstructDefinitions = ConstructDefinitions(
|
|
|
|
|
type: .Expression,
|
|
|
|
|
variants: [
|
|
|
|
|
"LiteralInteger": [
|
|
|
|
|
.Token(types: [.LITERAL_INTEGER])
|
|
|
|
|
.LiteralInteger: [
|
|
|
|
|
.Token(type: .LITERAL_INTEGER)
|
|
|
|
|
],
|
|
|
|
|
"UnaryOperator": [
|
|
|
|
|
.Token(types: [.NEGATION]),
|
|
|
|
|
.Token(types: UNARY_OPERATORS)
|
|
|
|
|
.Negation: [
|
|
|
|
|
.Token(type: .NEGATION),
|
|
|
|
|
.Token(type: .LITERAL_INTEGER)
|
|
|
|
|
],
|
|
|
|
|
.BitwiseCompliment: [
|
|
|
|
|
.Token(type: .BITWISE_COMPLIMENT),
|
|
|
|
|
.Token(type: .LITERAL_INTEGER)
|
|
|
|
|
],
|
|
|
|
|
.LogicalNegation: [
|
|
|
|
|
.Token(type: .LOGICAL_NEGATION),
|
|
|
|
|
.Token(type: .LITERAL_INTEGER)
|
|
|
|
|
],
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
@@ -59,10 +132,10 @@ let expression: ConstructDefinitions = ConstructDefinitions(
|
|
|
|
|
let statement: ConstructDefinitions = ConstructDefinitions(
|
|
|
|
|
type: .Statement,
|
|
|
|
|
variants: [
|
|
|
|
|
"ReturnInteger": [
|
|
|
|
|
.Token(types: [.RETURN]),
|
|
|
|
|
.ReturnInteger: [
|
|
|
|
|
.Token(type: .RETURN),
|
|
|
|
|
.Construct(type: expression),
|
|
|
|
|
.Token(types: [.SEMICOLON])
|
|
|
|
|
.Token(type: .SEMICOLON)
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
@@ -70,14 +143,14 @@ let statement: ConstructDefinitions = ConstructDefinitions(
|
|
|
|
|
let function: ConstructDefinitions = ConstructDefinitions(
|
|
|
|
|
type: .Function,
|
|
|
|
|
variants: [
|
|
|
|
|
"Integer": [
|
|
|
|
|
.Token(types: [.INT]),
|
|
|
|
|
.Token(types: [.IDENTIFIER]),
|
|
|
|
|
.Token(types: [.PARENTHESIS_OPEN]),
|
|
|
|
|
.Token(types: [.PARENTHESIS_CLOSE]),
|
|
|
|
|
.Token(types: [.BRACE_OPEN]),
|
|
|
|
|
.Integer: [
|
|
|
|
|
.Token(type: .INT),
|
|
|
|
|
.Token(type: .IDENTIFIER),
|
|
|
|
|
.Token(type: .PARENTHESIS_OPEN),
|
|
|
|
|
.Token(type: .PARENTHESIS_CLOSE),
|
|
|
|
|
.Token(type: .BRACE_OPEN),
|
|
|
|
|
.Construct(type: statement),
|
|
|
|
|
.Token(types: [.BRACE_CLOSE])
|
|
|
|
|
.Token(type: .BRACE_CLOSE)
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
@@ -85,7 +158,7 @@ let function: ConstructDefinitions = ConstructDefinitions(
|
|
|
|
|
let program: ConstructDefinitions = ConstructDefinitions(
|
|
|
|
|
type: .Function,
|
|
|
|
|
variants: [
|
|
|
|
|
"Function": [
|
|
|
|
|
.SingleFunction: [
|
|
|
|
|
.Construct(type: function)
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
@@ -154,7 +227,7 @@ func getTestFiles() -> [TestFile] {
|
|
|
|
|
var testFiles: [TestFile] = [TestFile]()
|
|
|
|
|
|
|
|
|
|
let fileManager = FileManager.default
|
|
|
|
|
let path = "c/tests/stage_2"
|
|
|
|
|
let path = "c/tests/stage_1"
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
let validItems = try fileManager.contentsOfDirectory(atPath: path + "/valid")
|
|
|
|
|
@@ -215,33 +288,62 @@ func parse(lexed: [Substring]) -> String {
|
|
|
|
|
}
|
|
|
|
|
tokens = tokens.reversed()
|
|
|
|
|
|
|
|
|
|
var output: String = ""
|
|
|
|
|
let abstractSyntaxTree = SyntaxTreeNode(.Root)
|
|
|
|
|
|
|
|
|
|
if validateConstruct(program.variants["Function"]!, constructType: .Function, tokens: &tokens, output: &output) {
|
|
|
|
|
if validateConstruct(program.variants[.SingleFunction]!, tokens: &tokens, node: abstractSyntaxTree) {
|
|
|
|
|
print("Success")
|
|
|
|
|
print(abstractSyntaxTree.text())
|
|
|
|
|
print("Assembly:")
|
|
|
|
|
print(output)
|
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
return output
|
|
|
|
|
let assembly: String = generateOutput(tree: abstractSyntaxTree)
|
|
|
|
|
print(assembly)
|
|
|
|
|
return assembly
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print("Distinct lack of success")
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func validateConstruct(_ construct: Construct, constructType: ConstructType, tokens: inout [Token], output: inout String) -> Bool {
|
|
|
|
|
func generateOutput(tree: SyntaxTreeNode) -> String {
|
|
|
|
|
var text: String = ""
|
|
|
|
|
switch tree.variant {
|
|
|
|
|
case .Integer:
|
|
|
|
|
text += " .globl \(tree.value)\n\(tree.value):\n"
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
case .ReturnInteger:
|
|
|
|
|
text += " movl $\(tree.children[0].value), %eax\n ret\n"
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for child in tree.children {
|
|
|
|
|
text += generateOutput(tree: child)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.type)\")")
|
|
|
|
|
|
|
|
|
|
var valid: Bool = false
|
|
|
|
|
var validVariant: String = ""
|
|
|
|
|
var validVariant: ConstructVariant = .Error
|
|
|
|
|
let tokenBackup: [Token] = tokens
|
|
|
|
|
for key in type.variants.keys {
|
|
|
|
|
if !validateConstruct(type.variants[key]!, constructType: type.type, tokens: &tokens, output: &output) {
|
|
|
|
|
let childNode = node.addChild(value: key)
|
|
|
|
|
print("Testing variant \(key)")
|
|
|
|
|
if !validateConstruct(type.variants[key]!, tokens: &tokens, node: childNode) {
|
|
|
|
|
print("Fail")
|
|
|
|
|
tokens = tokenBackup
|
|
|
|
|
_ = node.popLastChild()
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
print("Success")
|
|
|
|
|
valid = true
|
|
|
|
|
validVariant = key
|
|
|
|
|
break
|
|
|
|
|
@@ -251,16 +353,26 @@ func validateConstruct(_ construct: Construct, constructType: ConstructType, tok
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
print("End validate subconstruct (variant \"\(validVariant)\")")
|
|
|
|
|
break
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
|
|
case .Token(let type):
|
|
|
|
|
if let token: Token = tokens.popLast() {
|
|
|
|
|
if !type.contains(token.type) {
|
|
|
|
|
if type != token.type {
|
|
|
|
|
print("VALIDATION FAILED FOR TOKEN \"\(token.content)\"")
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
print("Validated token \"\(token.content)\"")
|
|
|
|
|
|
|
|
|
|
switch constructType {
|
|
|
|
|
if token.type == .LITERAL_INTEGER {
|
|
|
|
|
node.value = String(token.content)
|
|
|
|
|
}
|
|
|
|
|
else if token.type == .IDENTIFIER {
|
|
|
|
|
node.value = String(token.content)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
/*switch constructType {
|
|
|
|
|
case .Function:
|
|
|
|
|
if token.type == .IDENTIFIER {
|
|
|
|
|
output.append(" .globl \(token.content)\n\(token.content):\n")
|
|
|
|
|
@@ -273,7 +385,7 @@ func validateConstruct(_ construct: Construct, constructType: ConstructType, tok
|
|
|
|
|
break
|
|
|
|
|
default:
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
print("RAN OUT OF TOKENS")
|
|
|
|
|
@@ -294,7 +406,7 @@ func categorizeToken(token: Substring) -> TokenType {
|
|
|
|
|
else if token.firstMatch(of: /^int$/) != nil { return .INT }
|
|
|
|
|
else if token.firstMatch(of: /^return$/) != nil { return .RETURN }
|
|
|
|
|
else if token.firstMatch(of: /^[a-zA-Z]\w*$/) != nil { return .IDENTIFIER }
|
|
|
|
|
else if token.firstMatch(of: /^[0-9]+$/) != nil { return .LITERAL_INTEGER }
|
|
|
|
|
else if token.firstMatch(of: /^[0-9]+$/) != nil { return .LITERAL_INTEGER}
|
|
|
|
|
else if token.firstMatch(of: /^-$/) != nil { return .NEGATION }
|
|
|
|
|
else if token.firstMatch(of: /^~$/) != nil { return .BITWISE_COMPLIMENT }
|
|
|
|
|
else if token.firstMatch(of: /^!$/) != nil { return .LOGICAL_NEGATION }
|
|
|
|
|
|