Skip to content

Commit 516993e

Browse files
feat: add semantic analyzer to do type inference and add semi colons to support multiple statements
1 parent 85c516f commit 516993e

File tree

5 files changed

+116
-12
lines changed

5 files changed

+116
-12
lines changed

lex/lex.go

+12-6
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@ import (
55
"os"
66
"strings"
77
"unicode"
8-
9-
"github.com/k0kubun/pp"
108
)
119

1210
type Token interface {
1311
GetPos() (int, int)
1412
}
1513

14+
type Semicolon struct {
15+
Token
16+
Pos int
17+
End int
18+
}
19+
1620
type LBrace struct {
1721
Token
1822
Pos int
@@ -145,7 +149,7 @@ func LexSourceFile(sourceFile string) []Token {
145149
tokens = append(tokens, Number{Pos: pos, End: end, Value: numberValue.String(), Kind: kind})
146150
numberValue.Reset()
147151
}
148-
} else if isSymbol(char) && (unicode.IsLetter(rune(data[index+1])) || unicode.IsNumber(rune(data[index+1])) || data[index+1] == '(' || data[index+1] == ')' || data[index+1] == ' ' || data[index+1] == '\t' || data[index+1] == '\n') {
152+
} else if isSymbol(char) && (unicode.IsLetter(rune(data[index+1])) || unicode.IsNumber(rune(data[index+1])) || data[index+1] == '(' || data[index+1] == ')' || data[index+1] == ';' || data[index+1] == ' ' || data[index+1] == '\t' || data[index+1] == '\n') {
149153
if symbol.Len() != 0 {
150154
pos := index - len(symbol.String())
151155
end := index
@@ -170,14 +174,16 @@ func LexSourceFile(sourceFile string) []Token {
170174
tokens = append(tokens, Operator{Pos: pos, End: end, Kind: "-"})
171175
case "=":
172176
tokens = append(tokens, Operator{Pos: pos, End: end, Kind: "="})
177+
case ";":
178+
tokens = append(tokens, Semicolon{Pos: pos, End: end})
173179
}
174180
symbol.Reset()
175181
}
176182
}
177183
}
178184
}
179-
fmt.Println("The tokens are: ")
180-
pp.Println(tokens)
185+
// fmt.Println("The tokens are: ")
186+
// pp.Println(tokens)
181187
return tokens
182188
}
183189

@@ -191,5 +197,5 @@ func charIn(char byte, chars ...byte) bool {
191197
}
192198

193199
func isSymbol(char byte) bool {
194-
return charIn(char, '{', '}', '(', ')', ';', '+', '*', '/', '-', '=', '.')
200+
return charIn(char, '{', '}', '(', ')', ';', '+', '*', '/', '-', '=', '.', ';')
195201
}

main.fig

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
func Test {
2-
x = 100.50 + y * (3 + 5)
2+
y = 1 + 2;
3+
x = 1 + y * (3 + 5);
4+
z = x * y;
35
}
46

5-
func Test2 {
7+
func main {
68
}

main.go

+4
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ import (
66
_gen "github.com/ProgrammingMuffin/Fig/gen"
77
_lex "github.com/ProgrammingMuffin/Fig/lex"
88
_parse "github.com/ProgrammingMuffin/Fig/parse"
9+
_semantic "github.com/ProgrammingMuffin/Fig/semantic"
910
"github.com/k0kubun/pp/v3"
1011
)
1112

1213
func main() {
1314
tokens := _lex.LexSourceFile("main.fig")
1415
ast := _parse.ParseTokens(tokens)
16+
for _, astVal := range ast {
17+
_semantic.VisitNode(astVal)
18+
}
1519
pp.Println(ast)
1620
for _, astVal := range ast {
1721
_gen.VisitTree(astVal)

parse/parse.go

+18-4
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ func ParseBlock() (*_ast.Block, error) {
8989
block.RBrace = x.Pos
9090
return &block, nil
9191
}
92-
SafeInc()
9392
switch x := Tokens[Scan].(type) {
9493
case _lex.RBrace:
9594
block.RBrace = x.Pos
@@ -114,6 +113,10 @@ func ParseStatements() ([]_ast.Stmt, error) {
114113
if stmt != nil {
115114
stmts = append(stmts, stmt)
116115
} else {
116+
if err != nil {
117+
stmt, err = ParseStatement()
118+
stmts = append(stmts, stmt)
119+
}
117120
goto OUTSIDE
118121
}
119122
}
@@ -172,7 +175,11 @@ func ParseAssignStatement() (_ast.Stmt, error) {
172175
}
173176
switch Tokens[Scan].(type) {
174177
case _lex.Ident:
175-
return ParseStatement()
178+
nextStmt, err := ParseStatement()
179+
if err != nil {
180+
return nil, err
181+
}
182+
stmt.Rhs = nextStmt
176183
case _lex.LParen:
177184
term, err := ParseTerm()
178185
if err != nil {
@@ -183,13 +190,17 @@ func ParseAssignStatement() (_ast.Stmt, error) {
183190
return nil, err
184191
}
185192
stmt.Rhs = term
186-
return &stmt, nil
187193
case _lex.Number:
188194
nextStmt, err := ParseStatement()
189195
if err != nil {
190196
return nil, err
191197
}
192198
stmt.Rhs = nextStmt
199+
}
200+
SafeInc()
201+
switch Tokens[Scan].(type) {
202+
case _lex.Semicolon:
203+
SafeInc()
193204
return &stmt, nil
194205
}
195206
fmt.Println("error parsing assignment statement")
@@ -220,6 +231,8 @@ func ParseBinaryExpr(prev *_ast.BinaryExpr, prevTerm _ast.ExprStmt, prec int) (*
220231
binaryExpr := _ast.BinaryExpr{}
221232
if Scan+2 < len(Tokens) {
222233
switch x := Tokens[Scan+1].(type) {
234+
case _lex.Semicolon:
235+
return nil, nil
223236
case _lex.RBrace:
224237
return nil, nil
225238
case _lex.RParen:
@@ -236,6 +249,7 @@ func ParseBinaryExpr(prev *_ast.BinaryExpr, prevTerm _ast.ExprStmt, prec int) (*
236249
case _lex.Number:
237250
binaryExpr.Lhs = &_ast.BasicLit{
238251
Value: x.Value,
252+
Kind: x.Kind,
239253
}
240254
}
241255
if prev != nil {
@@ -265,7 +279,7 @@ func ParseBinaryExpr(prev *_ast.BinaryExpr, prevTerm _ast.ExprStmt, prec int) (*
265279
case _lex.Ident:
266280
binaryExpr.Rhs = &_ast.Ident{Value: x.Value, Pos: x.Pos, End: x.End}
267281
case _lex.Number:
268-
binaryExpr.Rhs = &_ast.BasicLit{Value: x.Value}
282+
binaryExpr.Rhs = &_ast.BasicLit{Value: x.Value, Kind: x.Kind}
269283
}
270284
}
271285
return &binaryExpr, nil

semantic/semantic.go

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package _semantic
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
_ast "github.com/ProgrammingMuffin/Fig/ast"
8+
"github.com/k0kubun/pp"
9+
)
10+
11+
var Symtab map[string]string = make(map[string]string) //matches symbol with type names
12+
13+
func VisitNode(node _ast.Node) {
14+
switch x := node.(type) {
15+
case *_ast.FuncDecl:
16+
VisitBlock(x.Block)
17+
}
18+
}
19+
20+
func VisitBlock(node _ast.Block) {
21+
for _, stmt := range node.Stmts {
22+
VisitStatement(stmt)
23+
}
24+
}
25+
26+
func VisitStatement(node _ast.Stmt) string {
27+
switch x := node.(type) {
28+
case *_ast.AssignStmt:
29+
x.Lhs.Type = VisitStatement(x.Rhs)
30+
Symtab[x.Lhs.Value] = x.Lhs.Type
31+
return x.Lhs.Type
32+
case *_ast.Term:
33+
return VisitStatement(x.ExprStmt)
34+
case *_ast.BinaryExpr:
35+
return VisitBinaryExpression(*x)
36+
}
37+
fmt.Println("type mismatch in statement")
38+
return ""
39+
}
40+
41+
func VisitBinaryExpression(node _ast.BinaryExpr) string {
42+
fmt.Println("symtab is : ")
43+
pp.Println(Symtab)
44+
type1 := ""
45+
type2 := ""
46+
switch x := node.Lhs.(type) {
47+
case *_ast.BasicLit:
48+
type1 = x.Kind
49+
case *_ast.BinaryExpr:
50+
type1 = VisitBinaryExpression(*x)
51+
case *_ast.Term:
52+
type1 = VisitStatement(x.ExprStmt)
53+
case *_ast.Ident:
54+
if val, ok := Symtab[x.Value]; ok {
55+
type1 = val
56+
x.Type = val
57+
}
58+
}
59+
switch x := node.Rhs.(type) {
60+
case *_ast.BasicLit:
61+
type2 = x.Kind
62+
case *_ast.BinaryExpr:
63+
type2 = VisitBinaryExpression(*x)
64+
case *_ast.Term:
65+
type2 = VisitStatement(x.ExprStmt)
66+
case *_ast.Ident:
67+
if val, ok := Symtab[x.Value]; ok {
68+
type2 = val
69+
x.Type = val
70+
}
71+
}
72+
if type1 == type2 && type1 != "" {
73+
return type1
74+
}
75+
fmt.Println("Type mismatch in binary expression")
76+
os.Exit(0)
77+
return type1
78+
}

0 commit comments

Comments
 (0)