Skip to content

Commit 5b63c9b

Browse files
committed
♻️ storing procedure body with its symbol in symbol table
1 parent c8f8efa commit 5b63c9b

File tree

9 files changed

+82
-127
lines changed

9 files changed

+82
-127
lines changed

PascalInterpreter/PascalInterpreter.xcodeproj/project.pbxproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
F34109A81FE2683900271A57 /* Visitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34109A71FE2683900271A57 /* Visitor.swift */; };
3333
F3EF28D01FE12EBF001F36AB /* Frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EF28CF1FE12EBF001F36AB /* Frame.swift */; };
3434
F3EF28D21FE12F4D001F36AB /* Stack.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EF28D11FE12F4D001F36AB /* Stack.swift */; };
35-
F3EF28FD1FE17754001F36AB /* SemanticData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EF28FC1FE17754001F36AB /* SemanticData.swift */; };
3635
/* End PBXBuildFile section */
3736

3837
/* Begin PBXContainerItemProxy section */
@@ -74,7 +73,6 @@
7473
F34109A71FE2683900271A57 /* Visitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Visitor.swift; sourceTree = "<group>"; };
7574
F3EF28CF1FE12EBF001F36AB /* Frame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Frame.swift; sourceTree = "<group>"; };
7675
F3EF28D11FE12F4D001F36AB /* Stack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stack.swift; sourceTree = "<group>"; };
77-
F3EF28FC1FE17754001F36AB /* SemanticData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SemanticData.swift; sourceTree = "<group>"; };
7876
/* End PBXFileReference section */
7977

8078
/* Begin PBXFrameworksBuildPhase section */
@@ -185,7 +183,6 @@
185183
isa = PBXGroup;
186184
children = (
187185
F300A0E41FDDB74700E5894D /* SemanticAnalyzer.swift */,
188-
F3EF28FC1FE17754001F36AB /* SemanticData.swift */,
189186
F300A0E21FDDB74700E5894D /* Symbol.swift */,
190187
F300A0E11FDDB74700E5894D /* Symbol+Extensions.swift */,
191188
F300A0E31FDDB74700E5894D /* SymbolTable.swift */,
@@ -356,7 +353,6 @@
356353
F300A0D81FDDB6F400E5894D /* AST+Extensions.swift in Sources */,
357354
F34109A81FE2683900271A57 /* Visitor.swift in Sources */,
358355
F300A0D11FDDB6E400E5894D /* Lexer.swift in Sources */,
359-
F3EF28FD1FE17754001F36AB /* SemanticData.swift in Sources */,
360356
F300A0D91FDDB6F400E5894D /* AST.swift in Sources */,
361357
F300A0E61FDDB74800E5894D /* Symbol.swift in Sources */,
362358
F300A0DE1FDDB71800E5894D /* Utils.swift in Sources */,

PascalInterpreter/PascalInterpreter/Interpreter/Frame.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ class Frame {
2121

2222
func set(variable: String, value: Number) {
2323
// variable define in current scole (procedure declataion, etc)
24-
if let symbol = scope.lookup(variable, currentScopeOnly: true), case .variable(name: _, .builtIn(let type)) = symbol {
24+
if let symbol = scope.lookup(variable, currentScopeOnly: true),
25+
let variableSymbol = symbol as? VariableSymbol,
26+
let type = variableSymbol.type as? BuiltInTypeSymbol {
27+
2528
switch type {
2629
case .integer:
2730
switch value {
@@ -47,7 +50,10 @@ class Frame {
4750

4851
func get(variable: String) -> Number {
4952
// variable define in current scole (procedure declataion, etc)
50-
if let symbol = scope.lookup(variable, currentScopeOnly: true), case .variable(name: _, .builtIn(let type)) = symbol {
53+
if let symbol = scope.lookup(variable, currentScopeOnly: true),
54+
let variableSymbol = symbol as? VariableSymbol,
55+
let type = variableSymbol.type as? BuiltInTypeSymbol {
56+
5157
switch type {
5258
case .integer:
5359
return .integer(integerMemory[variable]!)

PascalInterpreter/PascalInterpreter/Interpreter/Interpreter.swift

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,12 @@ public class Interpreter {
1212
private var callStack = Stack<Frame>()
1313
private let tree: AST
1414
private let scopes: [String: ScopedSymbolTable]
15-
private let procedures: [String: Procedure]
1615

1716
public init(_ text: String) {
1817
let parser = Parser(text)
1918
tree = parser.parse()
2019
let semanticAnalyzer = SemanticAnalyzer()
21-
let data = semanticAnalyzer.analyze(node: tree)
22-
scopes = data.scopes
23-
procedures = data.procedures
20+
scopes = semanticAnalyzer.analyze(node: tree)
2421
}
2522

2623
@discardableResult private func eval(node: AST) -> Number? {
@@ -131,25 +128,18 @@ public class Interpreter {
131128
}
132129

133130
private func callProcedure(procedure: String, params: [Number], frame: Frame) {
134-
guard let definition = procedures[procedure] else {
135-
fatalError("Procedure \(procedure) not in table, check SemanticAnalyzer implementation")
136-
}
137-
138-
guard let symbol = frame.scope.lookup(procedure), case let Symbol.procedure(name: _, params: declaredParams) = symbol else {
131+
guard let symbol = frame.scope.lookup(procedure), let procedureSymbol = symbol as? ProcedureSymbol else {
139132
fatalError("Symbol(procedure) not found '\(procedure)'")
140133
}
141134

142-
if declaredParams.count > 0 {
135+
if procedureSymbol.params.count > 0 {
143136

144-
for i in 0 ... declaredParams.count - 1 {
145-
guard case let Symbol.variable(name: name, type: Symbol.builtIn(_)) = declaredParams[i] else {
146-
fatalError("Procedure declared with wrong parameters '\(procedure)'")
147-
}
148-
frame.set(variable: name, value: params[i])
137+
for i in 0 ... procedureSymbol.params.count - 1 {
138+
frame.set(variable: procedureSymbol.params[i].name, value: params[i])
149139
}
150140
}
151141

152-
eval(node: definition.block)
142+
eval(node: procedureSymbol.body.block)
153143
}
154144

155145
public func interpret() {

PascalInterpreter/PascalInterpreter/Semantic analyzer/SemanticAnalyzer.swift

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ import Foundation
1111
public class SemanticAnalyzer: Visitor {
1212
private var currentScope: ScopedSymbolTable?
1313
private var scopes: [String: ScopedSymbolTable] = [:]
14-
private var procedures: [String: Procedure] = [:]
1514

1615
public init() {
1716

1817
}
1918

20-
public func analyze(node: AST) -> SemanticData {
19+
public func analyze(node: AST) -> [String: ScopedSymbolTable] {
2120
visit(node: node)
22-
return SemanticData(scopes: scopes, procedures: procedures)
21+
return scopes
2322
}
2423

2524
func visit(program: Program) {
@@ -52,7 +51,7 @@ public class SemanticAnalyzer: Visitor {
5251
fatalError("Type not found '\(variableDeclaration.type.type.description)'")
5352
}
5453

55-
scope.insert(.variable(name: variableDeclaration.variable.name, type: symbolType))
54+
scope.insert(VariableSymbol(name: variableDeclaration.variable.name, type: symbolType))
5655
}
5756

5857
func visit(procedure: Procedure) {
@@ -65,33 +64,32 @@ public class SemanticAnalyzer: Visitor {
6564
guard let symbol = scope.lookup(param.type.type.description) else {
6665
fatalError("Type not found '\(param.type.type.description)'")
6766
}
68-
let variable = Symbol.variable(name: param.name, type: symbol)
67+
let variable = VariableSymbol(name: param.name, type: symbol)
6968
parameters.append(variable)
7069
scope.insert(variable)
7170
}
72-
let proc = Symbol.procedure(name: procedure.name, params: parameters)
71+
let proc = ProcedureSymbol(name: procedure.name, parameters: parameters, body: procedure)
7372
scope.enclosingScope?.insert(proc)
7473

7574
visit(node: procedure.block)
76-
procedures[procedure.name] = procedure
7775
currentScope = currentScope?.enclosingScope
7876
}
7977

8078
func visit(call: ProcedureCall) {
81-
guard let symbol = currentScope?.lookup(call.name), case let Symbol.procedure(name: _, params: declaredParams) = symbol else {
79+
guard let symbol = currentScope?.lookup(call.name), let procedure = symbol as? ProcedureSymbol else {
8280
fatalError("Symbol(procedure) not found '\(call.name)'")
8381
}
8482

85-
guard declaredParams.count == call.actualParameters.count else {
83+
guard procedure.params.count == call.actualParameters.count else {
8684
fatalError("Procedure called with wrong number of parameters '\(call.name)'")
8785
}
8886

89-
guard declaredParams.count > 0 else {
87+
guard procedure.params.count > 0 else {
9088
return
9189
}
9290

93-
for i in 0 ... declaredParams.count - 1 {
94-
guard case let Symbol.variable(name: _, type: Symbol.builtIn(type)) = declaredParams[i] else {
91+
for i in 0 ... procedure.params.count - 1 {
92+
guard let variableSymbol = procedure.params[i] as? VariableSymbol, let type = variableSymbol.type as? BuiltInTypeSymbol else {
9593
fatalError("Procedure declared with wrong parameters '\(call.name)'")
9694
}
9795

PascalInterpreter/PascalInterpreter/Semantic analyzer/SemanticData.swift

Lines changed: 0 additions & 14 deletions
This file was deleted.

PascalInterpreter/PascalInterpreter/Semantic analyzer/Symbol+Extensions.swift

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,57 +8,34 @@
88

99
import Foundation
1010

11-
extension BuiltInType: CustomStringConvertible {
11+
extension BuiltInTypeSymbol: CustomStringConvertible {
1212
public var description: String {
1313
return "<BuiltinTypeSymbol(name='\(self.name)')>"
1414
}
15-
16-
public var name: String {
17-
switch self {
18-
case .integer:
19-
return "INTEGER"
20-
case .real:
21-
return "REAL"
22-
}
23-
}
2415
}
25-
26-
extension Symbol: CustomStringConvertible {
16+
extension VariableSymbol: CustomStringConvertible {
2717
public var description: String {
28-
switch self {
29-
case let .builtIn(type):
30-
return type.description
31-
case let .variable(name: name, type: type):
32-
return "<VarSymbol(name='\(name)', type='\(type.name)')>"
33-
case let .procedure(name: name, params: params):
34-
return "<ProcedureSymbol(name=\(name), parameters=[\(params.reduce("", { $0.description + "," + $1.description }))]>"
35-
}
18+
return "<VarSymbol(name='\(name)', type='\(type.name)')>"
3619
}
3720
}
3821

39-
extension Symbol: Equatable {
40-
public static func == (lhs: Symbol, rhs: Symbol) -> Bool {
41-
switch (lhs, rhs) {
42-
case let (.builtIn(left), .builtIn(right)):
43-
return left == right
44-
case let (.variable(name: leftName, type: leftType), .variable(name: rightName, type: rightType)):
45-
return leftName == rightName && leftType == rightType
46-
default:
47-
return false
48-
}
22+
extension ProcedureSymbol: CustomStringConvertible {
23+
public var description: String {
24+
return "<ProcedureSymbol(name=\(name), parameters=[\(params.reduce("", { $0.description + "\($1)," }))]>"
4925
}
50-
5126
}
5227

5328
extension Symbol {
54-
public var name: String {
29+
var sortOrder: Int {
5530
switch self {
56-
case let .builtIn(type):
57-
return type.name
58-
case .procedure(name: let name, params: _):
59-
return name
60-
case .variable(name: let name, type: _):
61-
return name
31+
case is BuiltInTypeSymbol:
32+
return 0
33+
case is VariableSymbol:
34+
return 1
35+
case is ProcedureSymbol:
36+
return 2
37+
default:
38+
fatalError("Add sort order for \(self)")
6239
}
6340
}
6441
}

PascalInterpreter/PascalInterpreter/Semantic analyzer/Symbol.swift

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,42 @@
88

99
import Foundation
1010

11-
public enum BuiltInType {
11+
protocol Symbol {
12+
var name: String { get }
13+
}
14+
15+
public enum BuiltInTypeSymbol: Symbol {
1216
case integer
1317
case real
18+
19+
var name: String {
20+
switch self {
21+
case .integer:
22+
return "INTEGER"
23+
case .real:
24+
return "REAL"
25+
}
26+
}
1427
}
1528

16-
public indirect enum Symbol {
17-
case builtIn(BuiltInType)
18-
case variable(name: String, type: Symbol)
19-
case procedure(name: String, params: [Symbol])
29+
class VariableSymbol: Symbol {
30+
let name: String
31+
let type: Symbol
32+
33+
init(name: String, type: Symbol) {
34+
self.name = name
35+
self.type = type
36+
}
37+
}
38+
39+
class ProcedureSymbol: Symbol {
40+
let name: String
41+
let params: [Symbol]
42+
let body: Procedure
43+
44+
init(name: String, parameters: [Symbol], body: Procedure) {
45+
self.name = name
46+
self.params = parameters
47+
self.body = body
48+
}
2049
}

PascalInterpreter/PascalInterpreter/Semantic analyzer/SymbolTable.swift

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ public class ScopedSymbolTable {
2020
self.level = level
2121
self.enclosingScope = enclosingScope
2222

23-
insert(.builtIn(.integer))
24-
insert(.builtIn(.real))
23+
insert(BuiltInTypeSymbol.integer)
24+
insert(BuiltInTypeSymbol.real)
2525
}
2626

2727
func insert(_ symbol: Symbol) {
@@ -41,47 +41,16 @@ public class ScopedSymbolTable {
4141
}
4242
}
4343

44-
extension ScopedSymbolTable: Equatable {
45-
public static func == (lhs: ScopedSymbolTable, rhs: ScopedSymbolTable) -> Bool {
46-
if lhs.symbols.keys != rhs.symbols.keys {
47-
return false
48-
}
49-
50-
for key in lhs.symbols.keys where lhs.symbols[key] != rhs.symbols[key] {
51-
return false
52-
}
53-
54-
return true
55-
}
56-
}
57-
5844
extension ScopedSymbolTable: CustomStringConvertible {
5945
public var description: String {
6046
var lines = ["SCOPE (SCOPED SYMBOL TABLE)", "==========================="]
6147
lines.append("Scope name : \(name)")
6248
lines.append("Scope level : \(level)")
6349
lines.append("Scope (Scoped symbol table) contents")
6450
lines.append("------------------------------------")
65-
for pair in symbols.sorted(by: { lhs, rhs -> Bool in
66-
switch (lhs.value, rhs.value) {
67-
case (.builtIn, .builtIn):
68-
return lhs.key < rhs.key
69-
case (.builtIn, .variable):
70-
return true
71-
case (.variable, .builtIn):
72-
return false
73-
case (.variable, .variable):
74-
return lhs.key < rhs.key
75-
case (.procedure, .procedure):
76-
return lhs.key < rhs.key
77-
case (.procedure, _):
78-
return false
79-
case (_, .procedure):
80-
return true
81-
}
82-
}) {
83-
lines.append("\(pair.key.padding(toLength: 7, withPad: " ", startingAt: 0)): \(pair.value)")
84-
}
51+
lines.append(contentsOf: symbols.sorted(by: {$0.value.sortOrder < $1.value.sortOrder}).map({ key, value in
52+
return "\(key.padding(toLength: 7, withPad: " ", startingAt: 0)): \(value)"
53+
}))
8554
return lines.reduce("", { $0 + "\n" + $1 })
8655
}
8756
}

Playground.playground/Contents.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ let node = parser.parse()
3434
node.printTree()
3535
print("")
3636

37+
let analyzer = SemanticAnalyzer()
38+
let result = analyzer.analyze(node: node)
39+
print(result)
40+
3741
let interpreter = Interpreter(program)
3842
interpreter.interpret()
3943
print("")

0 commit comments

Comments
 (0)