Skip to content

Commit 6c7d990

Browse files
committed
🚧 working semantic analyzer with nested scopes (breaking the interpreter)
1 parent f6e9c5f commit 6c7d990

File tree

2 files changed

+43
-13
lines changed

2 files changed

+43
-13
lines changed

‎PascalInterpreter/PascalInterpreter/Semantic analyzer/SemanticAnalyzer.swift‎

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
import Foundation
1010

1111
public class SemanticAnalyzer {
12-
private let symbolTable = ScopedSymbolTable(name: "global", level: 1)
12+
private var currentScope: ScopedSymbolTable?
1313

1414
public init() {
1515

1616
}
1717

1818
public func build(node: AST) -> ScopedSymbolTable {
1919
visit(node: node)
20-
return symbolTable
20+
return ScopedSymbolTable(name: "global", level: 1, enclosingScope: nil)
2121
}
2222

2323
private func visit(node: AST) {
@@ -28,7 +28,11 @@ public class SemanticAnalyzer {
2828
}
2929
visit(node: compoundStatement)
3030
case let .program(name: _, block: block):
31+
let globalScope = ScopedSymbolTable(name: "global", level: 1, enclosingScope: nil)
32+
currentScope = globalScope
3133
visit(node: block)
34+
print(globalScope)
35+
currentScope = nil
3236
case let .binaryOperation(left: left, operation: _, right: right):
3337
visit(node: left)
3438
visit(node: right)
@@ -43,41 +47,57 @@ public class SemanticAnalyzer {
4347
case .noOp:
4448
break
4549
case let .variable(name):
46-
guard symbolTable.lookup(name) != nil else {
50+
guard let scope = currentScope else {
51+
fatalError("Cannot access a variable outside a scope")
52+
}
53+
guard scope.lookup(name) != nil else {
4754
fatalError("Symbol(indetifier) not found '\(name)'")
4855
}
4956
case let .variableDeclaration(name: variable, type: variableType):
57+
guard let scope = currentScope else {
58+
fatalError("Cannot declare a variable outside a scope")
59+
}
60+
5061
guard case let .variable(name) = variable, case let .type(type) = variableType else {
5162
fatalError("Invalid variable \(variable) or invalid type \(variableType)")
5263
}
5364

54-
guard symbolTable.lookup(name) == nil else {
65+
guard scope.lookup(name, currentScopeOnly: true) == nil else {
5566
fatalError("Duplicate identifier '\(name)' found")
5667
}
5768

58-
guard let symbolType = symbolTable.lookup(type.description) else {
69+
guard let symbolType = scope.lookup(type.description) else {
5970
fatalError("Type not found '\(type.description)'")
6071
}
6172

62-
symbolTable.insert(.variable(name: name, type: symbolType))
73+
scope.insert(.variable(name: name, type: symbolType))
6374
case let .assignment(left: left, right: right):
6475
visit(node: right)
6576
visit(node: left)
6677
case .type:
6778
break
68-
case let .procedure(name: name, params: params, block: _):
79+
case let .procedure(name: name, params: params, block: block):
80+
let scope = ScopedSymbolTable(name: name, level: (currentScope?.level ?? 0) + 1, enclosingScope: currentScope)
81+
currentScope = scope
82+
6983
var parameters: [Symbol] = []
7084
for param in params {
7185
guard case let .param(name: name, type: .type(type)) = param else {
7286
fatalError("Only built int type parameters supported in procedure, got \(param)")
7387
}
74-
guard let symbol = symbolTable.lookup(type.description) else {
88+
guard let symbol = scope.lookup(type.description) else {
7589
fatalError("Type not found '\(type.description)'")
7690
}
77-
parameters.append(.variable(name: name, type: symbol))
91+
let variable = Symbol.variable(name: name, type: symbol)
92+
parameters.append(variable)
93+
scope.insert(variable)
7894
}
7995
let symbol = Symbol.procedure(name: name, params: parameters)
80-
symbolTable.insert(symbol)
96+
scope.insert(symbol)
97+
98+
visit(node: block)
99+
print(scope)
100+
currentScope = currentScope?.enclosingScope
81101
case .param:
82102
break
83103
}

‎PascalInterpreter/PascalInterpreter/Semantic analyzer/SymbolTable.swift‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ public class ScopedSymbolTable {
1313

1414
let name: String
1515
let level: Int
16+
let enclosingScope: ScopedSymbolTable?
1617

17-
init(name: String, level: Int) {
18+
init(name: String, level: Int, enclosingScope: ScopedSymbolTable?) {
1819
self.name = name
1920
self.level = level
21+
self.enclosingScope = enclosingScope
2022

2123
insert(.builtIn(.integer))
2224
insert(.builtIn(.real))
@@ -26,8 +28,16 @@ public class ScopedSymbolTable {
2628
symbols[symbol.name] = symbol
2729
}
2830

29-
func lookup(_ name: String) -> Symbol? {
30-
return symbols[name]
31+
func lookup(_ name: String, currentScopeOnly: Bool = false) -> Symbol? {
32+
if let symbol = symbols[name] {
33+
return symbol
34+
}
35+
36+
if currentScopeOnly {
37+
return nil
38+
}
39+
40+
return enclosingScope?.lookup(name)
3141
}
3242
}
3343

0 commit comments

Comments
 (0)