在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
一、语法分析 通过将词法分析获取的Token流按照目标语言的语法进行解析的过程,例如解析函数声明、函数调用、变量声明、各种语句等。
二、Lua语法分析 在写语法分析程序前,先需要了解Lua的语句和语法,然后进行逐个解析。 下面简单列举一下Lua的语句: 1. 函数定义 1 -- 普通的函数声明 2 function demo1() 3 -- <函数体> 4 end 5 -- 类方法 6 function t.demo2(self) 7 -- <函数体> 8 end 9 -- 方法调用中的匿名函数(其实还有很多) 10 some_method_call(arg1, function() <callback> end) 2. 函数调用 1 -- 普通的函数调用 2 print("Hello Lua") 3 -- 模块方法 4 math.random(1,2) 5 -- 类方法 6 obj:set_id(xx) 3. 赋值语句 1 -- 带local局部变量声明赋值 2 local a = 1 3 -- 多变量 4 local a,b,c = 2,3 5 -- 全局的变量 6 g_a = 3 7 -- 赋值可以是函数、函数调用、表等 8 g_c,g_b = {}, function() end 4. 条件分支 1 -- if条件分支 2 if a > 1 then 3 elseif a > 2 then 4 else 5 end 5. for循环 1 -- for循环 2 for i=1,10,2 do 3 end 6. for迭代器 1 -- 迭代包含in pairs 和 in ipairs 2 for k,v in pairs(tb) do 3 end 7. while循环 1 -- while循环,条件可以很复杂 2 while a >1 and b > 1 do 3 end 8. repeat until 循环 1 repeat 2 until a > 1
上面仅仅简单了进行了举例,实际上项目中的写法是千奇百怪的,因此需要确保包含所有的语法规则。在进行语法解析的时候,首先进行代码块的解析,可以把一个文件看作整个代码块,里面包含各种的语句。然后其实是逐语句解析,先取出一个Token,判断这个Token的类型,然后决定更细规则的解析,就像下面代码列举的过程一样。 1. 语法解析的入口,调用block解析。 1 def parse(self): 2 self._TokenNum = self.mTokens 3 block = self.on_block_parse() 4 return block 2. 对block解析的时候,实际是循环调用逐语句解析,直到匹配到语句块结束标记。 1 def on_block_parse(self): 2 token = self.get_token() 3 statements = [] 4 while token is not None: 5 # until,else,elseif,end 6 if self.is_end_token(token): 7 self.put_token() 8 break 9 # 语句解析 10 statement = self.on_statement_parse(token) 11 if not statement: 12 break 13 statements.append(statement) 14 token = self.get_token() 15 return Block(statements) 3. 逐语句解析就是获取Token的类型,并调用对应类型的解析方法。 1 def on_statement_parse(self, token): 2 # 函数 3 if token.tokenType == T.FUNCTION: 4 return self.on_function_parse(token) 5 # for .. in .. do .. end 6 elif token.tokenType == T.FOR: 7 return self.on_for_parse(token) 8 # while .. do .. end 9 elif token.tokenType == T.WHILE: 10 return self.on_while_parse(token) 11 # repeat ... until xx 12 elif token.tokenType == T.REPEAT: 13 return self.on_repeat_parse(token) 14 # if .. elseif ... else .. end 15 elif token.tokenType == T.IF: 16 return self.on_if_parse(token) 17 # do ... end 18 elif token.tokenType == T.DO: 19 return self.on_do_parse(token) 20 # local xx 21 elif token.tokenType == T.LOCAL: 22 return self.on_local_parse(token) 23 # return xxx 24 elif token.tokenType == T.RETURN: 25 return self.on_return_parse(token) 26 else: 27 return self.on_expression_parse(token) 4. 列举一下while循环的解析,其中会调用表达式解析while的条件,调用block解析while的语句体,然后检查是否有end。基本上其他的语句也是按照这样的方式进行分析与解析。 1 def on_while_parse(self, token): 2 """ while 循环 """ 3 # while <condition> do 4 exp = self.on_expression_parse(self.get_token()) 5 if not exp: 6 self.print_syntax_error(token) 7 return None 8 next_token = self.get_token() 9 if next_token.text != 'do': 10 self.print_syntax_error(next_token) 11 return 12 body = self.on_block_parse() 13 next_token = self.get_token() 14 if next_token.text != 'end': 15 self.print_syntax_error(next_token) 16 return None 17 while_statement = LNodeWhile(token.lineno, exp, body) 18 return while_statement 三、总结 通过上面的简单介绍,不知可能上手写一写呢?将所有的语句都解析完成后,接下来就是进行静态代码扫描了。如果是使用C或者C++写的话,完全可以从Lua的源码中提取上面的词法和语法解析内容,而直接进行代码规则扫描检查的编写。 文章来自我的公众号,大家如果有兴趣可以关注,具体扫描关注下图。 |
请发表评论