0%

Js-Go:完善语句+对象处理

语法分析

完善 if while for 语句:

1
2
3
| 'if' '(' expr ')' block ('else' block)?
| 'while' '(' expr ')' block
| 'for' '(' stm? ';' stm? ';' stm? ')' block

对应的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
if str_1 == "return" {
value, typ = handExpr(stm.GetChild(1).(*Jsp.ExprContext))
return value, typ, true
}
if str_1 == "var" {
name := fmt.Sprintf("%v", stm.GetChild(1))
str_2 = fmt.Sprintf("%v", stm.GetChild(2))
if str_2 == "=" {
vaule, typ := handExpr(stm.GetChild(3).(*Jsp.ExprContext))
vl.addVar(name, vaule, typ)
if typ == Jsp.JavaScriptParserRULE_obj {
vl.setVarAll(name)
vl.showVarAll()
}
}
vl.showVarAll()
}
if str_1 == "if" {
vaule, typ := handExpr(stm.GetChild(2).(*Jsp.ExprContext))
if ok := checkExpr(vaule, typ); ok {
handBlock(stm.GetChild(4).(*Jsp.BlockContext))
} else if stm.GetChildCount() == 6 {
handBlock(stm.GetChild(6).(*Jsp.BlockContext))
}
}
if str_1 == "while" {
for {
vaule, typ := handExpr(stm.GetChild(2).(*Jsp.ExprContext))
if ok := checkExpr(vaule, typ); !ok {
break
}
handBlock(stm.GetChild(4).(*Jsp.BlockContext))
}
}
if str_1 == "for" {
var smts [3]*Jsp.StmContext
var index int = 0

for _, c := range stm.GetChildren() {
_, ok := c.(*Jsp.StmContext)
if tmp := fmt.Sprintf("%v", c); tmp == ";" {
index++
}
if c.GetChild(0) != nil && ok {
smts[index] = c.(*Jsp.StmContext)
}
}
if smts[0] != nil {
handStm(smts[0])
}

for {
if smts[1] != nil {
vaule, typ, _ := handStm(smts[1])
if ok := checkExpr(vaule, typ); !ok {
break
}
}
handBlock(stm.GetChild(stm.GetChildCount() - 1).(*Jsp.BlockContext))
if smts[2] != nil {
handStm(smts[2])
}
}
}

为了匹配 if 语句,需要给表达式语句添加对于条件语句的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
if op == ">" {
if typ1 == Jsp.JavaScriptLexerNUMBER && typ2 == Jsp.JavaScriptLexerNUMBER {
num1, _ := strconv.Atoi(exp1)
num2, _ := strconv.Atoi(exp2)
return strconv.FormatBool(num1 > num2), Jsp.JavaScriptParserRULE_bool
} else {
return "", -1
}
}
if op == ">=" {
if typ1 == Jsp.JavaScriptLexerNUMBER && typ2 == Jsp.JavaScriptLexerNUMBER {
num1, _ := strconv.Atoi(exp1)
num2, _ := strconv.Atoi(exp2)
return strconv.FormatBool(num1 >= num2), Jsp.JavaScriptParserRULE_bool
} else {
return "", -1
}
}
if op == "<" {
if typ1 == Jsp.JavaScriptLexerNUMBER && typ2 == Jsp.JavaScriptLexerNUMBER {
num1, _ := strconv.Atoi(exp1)
num2, _ := strconv.Atoi(exp2)
return strconv.FormatBool(num1 < num2), Jsp.JavaScriptParserRULE_bool
} else {
return "", -1
}
}
if op == "<=" {
if typ1 == Jsp.JavaScriptLexerNUMBER && typ2 == Jsp.JavaScriptLexerNUMBER {
num1, _ := strconv.Atoi(exp1)
num2, _ := strconv.Atoi(exp2)
return strconv.FormatBool(num1 <= num2), Jsp.JavaScriptParserRULE_bool
} else {
return "", -1
}
}
if op == "==" {
if typ1 == Jsp.JavaScriptLexerNUMBER && typ2 == Jsp.JavaScriptLexerNUMBER {
num1, _ := strconv.Atoi(exp1)
num2, _ := strconv.Atoi(exp2)
return strconv.FormatBool(num1 == num2), Jsp.JavaScriptParserRULE_bool
} else {
return "", -1
}
}
if op == "!=" {
if typ1 == Jsp.JavaScriptLexerNUMBER && typ2 == Jsp.JavaScriptLexerNUMBER {
num1, _ := strconv.Atoi(exp1)
num2, _ := strconv.Atoi(exp2)
return strconv.FormatBool(num1 != num2), Jsp.JavaScriptParserRULE_bool
} else {
return "", -1
}
}

另外还添加了对于语句块的处理:

1
2
3
4
5
6
7
8
9
10
11
func handBlock(blo *Jsp.BlockContext) (string, int) {
for _, c := range blo.GetChildren() {
if c.GetChild(0) != nil {
value, typ, ok := handStm(c.(*Jsp.StmContext))
if ok {
return value, typ
}
}
}
return "", -1
}

为了实现对象处理,我这里对许多地方进行了修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
if exp.GetChildCount() == 1 {
if call, ok := exp.GetChild(0).(*Jsp.FuncallContext); ok {
return handExpr_funcall(call)
} else if obj, ok := exp.GetChild(0).(*Jsp.ObjContext); ok {
for _, o := range obj.GetChildren() {
if o.GetChild(0) != nil {
name := fmt.Sprintf("%v", o.GetChild(0).GetChild(0))
value, typ := handExpr(o.GetChild(2).(*Jsp.ExprContext))
vl.addVar("*."+name, value, typ)
}
}
return "", Jsp.JavaScriptParserRULE_obj
} else {
renum := regexp.MustCompile(`^\d+$`)
resym := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
str := fmt.Sprintf("%v", exp.GetChild(0).GetChild(0))
if str[0] == '"' {
return str, Jsp.JavaScriptLexerSTRING
}
if renum.MatchString(str) {
return str, Jsp.JavaScriptLexerNUMBER
}
if resym.MatchString(str) {
value, typ := vl.getVarByName(str)
return value, typ
}
}
}
  • 当匹配到 Jsp.ObjContext 时,程序会将该对象的各个条目装入动态符号表 SymTable,形成如下结构:
1
2
3
4
5
6
7
|----------SymTable--------------------------------------|
|name type value |
|--------------------------------------------------------|
|globol.*.type 20 "porsche" |
|globol.*.model 20 "911" |
|globol.*.color 20 "white" |
|--------------------------------------------------------|
  • 此时的对象条目并不能被直接使用,只有第一次使用该对象时才会再次进行初始化,然后形成如下结构:
1
2
3
4
5
6
7
8
|----------SymTable--------------------------------------|
|name type value |
|--------------------------------------------------------|
|globol.car.type 20 "porsche" |
|globol.car.model 20 "911" |
|globol.car.color 20 "white" |
|globol.car 5 {car} |
|--------------------------------------------------------|

对应的代码如下:

1
2
3
4
5
6
7
8
if str_2 == "=" {
vaule, typ := handExpr(stm.GetChild(3).(*Jsp.ExprContext))
vl.addVar(name, vaule, typ)
if typ == Jsp.JavaScriptParserRULE_obj {
vl.setVarAll(name)
vl.showVarAll()
}
}
  • 这样的处理保证了没有被引用的对象不会被 SymTable 使用,但同时它们也被永远遗留在了 SymTable 中
  • 其实有考虑过将 SymTable 中不使用的对象数据给清除掉,但考虑到后续可能会想到更好的处理方式,便没有写清除 SymTable 的代码

最后在表达式处理中添加了关于对象引用的代码:

1
2
3
4
5
6
if op == "." {
name1 := exp1[1 : len(exp1)-1]
name2 := fmt.Sprintf("%v", exp.GetChild(2).GetChild(0).GetChild(0))
value, typ := vl.getVarByName(name1 + op + name2)
return value, typ
}
  • 我这里直接将对象引用 . 当成了一种运算符号,然后强行合并到二元运算符的处理中
  • 这部分代码返回的上层代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if exp1, ok := stm.GetChild(0).(*Jsp.ExprContext); ok {
value, typ = handExpr(exp1)
if str_2 == "=" {
if exp2, ok := stm.GetChild(2).(*Jsp.ExprContext); ok {
var name string
value2, typ2 := handExpr(exp2)

if exp1.GetChild(0).GetChild(0).GetChild(0) == nil {
name = fmt.Sprintf("%v", exp1.GetChild(0).GetChild(0))
} else {
name = fmt.Sprintf("%v", exp1.GetChild(0).GetChild(0).GetChild(0))
name += "."
name += fmt.Sprintf("%v", exp1.GetChild(2).GetChild(0).GetChild(0))
}
vl.setVar(name, value2, typ2)
}
}
}
  • 目前看上去有点勉强,之后会考虑优化