使用PLY.yacc的正确解析策略>> [

问题描述 投票:0回答:1
我正在用PLY编写PHP解析器,以自学词法分析的概念。

我为一个非常简单的PHP代码段创建了lexer令牌,但是我仍然坚持正确的解析方法。

这是我要尝试解析/解析的代码段:

<?php if (isset($_REQUEST['name'])){ $name = $_REQUEST['name']; $msg = "Hello, " . $name . "!"; $encoded = htmlspecialchars($msg); } ?>

我的目标是跟踪用户输入以确定确实已达到htmlspecialchars()方法。我当前的解析策略使我对第2行的解析更深入。

$name = $_REQUEST['name'];

但我不知道解析第3行的正确方法是什么

$msg = "Hello, " . $name . "!";

复杂之处在于,我永远无法确定用户输入上会发生多少级联,我觉得仅仅为了成功解析示例代码而“硬编码”是错误的。例如,对于这一行,我对$msg变量包括我的用户提供的数据(来自$name变量)

我已经尝试以最坏的可能方式解析此令牌,只是为了测试是否可以到达它,但是当我运行脚本时,它说WARNING: Symbol 'wrong' is unreachable

def p_wrong(p): '''wrong : VARIABLE EQUALS QUOTED_ENCAPSED_STRING DOT VARIABLE DOT QUOTED_ENCAPSED_STRING SEMICOLON''' print "wrong"

因此,我希望获得指导,以帮助我理解如何解析第3行,这样对跟踪的变量进行多少次串联或其他操作都无关紧要。我觉得这是开始BNF语法课程或非常痛苦的解析复杂性的起点。但是我想学习,我只是不知道从哪里开始。

这是我的完整代码:

import ply.lex as lex import ply.yacc as yacc string = """<?php if (isset($_REQUEST['name'])){ $name = $_REQUEST['name']; $msg = "Hello, " . $name . "!"; $encoded = htmlspecialchars($msg); } ?>""" delimeters = ('LPAREN', 'RPAREN', 'LBRACKET', 'RBRACKET') tokens = delimeters + ( "CHAR", "NUM", "OPEN_TAG", "CLOSE_TAG", "VARIABLE", "CONSTANT_ENCAPSED_STRING", "ENCAPSED_AND_WHITESPACE", "QUOTED_ENCAPSED_STRING", "LCURLYBRACKET", "RCURLYBRACKET", "EQUALS", "SEMICOLON", "QUOTE", "DOT", "IF" ) t_ignore = " \t" t_CHAR = r"[a-z]" t_LPAREN = r'\(' t_RPAREN = r'\)' t_RBRACKET = r'\]' t_LBRACKET = r'\[' t_RCURLYBRACKET = r'\}' t_LCURLYBRACKET = r'\{' t_EQUALS = r'=' t_SEMICOLON = r';' t_DOT = r'\.' def t_newline(t): r'\n+' t.lexer.lineno += t.value.count("\n") def t_CONSTANT_ENCAPSED_STRING(t): r"'([^\\']|\\(.|\n))*'" t.lexer.lineno += t.value.count("\n") return t def t_QUOTED_ENCAPSED_STRING(t): r"""\"([^\\"]|\\(.|\n))*\"""" t.lexer.lineno += t.value.count("\n") return t def t_OPEN_TAG(t): r'<[?%]((php[ \t\r\n]?)|=)?' if '=' in t.value: t.type = 'OPEN_TAG_WITH_ECHO' t.lexer.lineno += t.value.count("\n") return t def t_CLOSE_TAG(t): r'[?%]>\r?\n?' t.lexer.lineno += t.value.count("\n") #t.lexer.begin('INITIAL') return t def t_VARIABLE(t): r'\$[A-Za-z_][\w_]*' return t def t_NUM(t): r"\d+" t.value = int(t.value) return t def t_error(t): print t.lexer.current_state print dir(t.lexer) raise TypeError("unknown char '%s'"%(t.value)) lexer = lex.lex() lex.input(string) for tok in iter(lex.token, None): print repr(tok.type), repr(tok.value) ##now for the parsing """ $name = $_REQUEST['name']; $msg = "Hello, " . $name . "!"; """ def p_assign(p): '''assign : VARIABLE EQUALS input''' print "assign rule" print p[1],p[2],p[3] p[0] = p[1] def p_input(p): '''input : VARIABLE LBRACKET CONSTANT_ENCAPSED_STRING RBRACKET SEMICOLON | VARIABLE LBRACKET QUOTED_ENCAPSED_STRING RBRACKET SEMICOLON''' print "input rule" value = p[1]+p[2]+p[3]+p[4]+p[5] p[0] = value def p_wrong(p): '''wrong : VARIABLE EQUALS QUOTED_ENCAPSED_STRING DOT VARIABLE DOT QUOTED_ENCAPSED_STRING SEMICOLON''' print "wrong" yacc.yacc() yacc.parse(string)

结果:

... WARNING: There is 1 unused rule WARNING: Symbol 'wrong' is unreachable Generating LALR tables yacc: Syntax error at line 6, token=OPEN_TAG input rule assign rule $name = $_REQUEST['name']; yacc: Syntax error at line 8, token=VARIABLE

我(不正确)尝试解析第3行(使用解析器规则p_wrong硬编码的格式)甚至没有成功。但我只想了解一些有关如何继续解析此简单代码块的指导。

所需的输出

理想情况下,我将获得结果,使我可以跟踪用户输入,如下所示:

user-input -> $name -> $msg -> htmlspecialchars($msg)

我正在用PLY编写PHP解析器,以自学词法分析的概念。我为一个非常简单的PHP代码段创建了lexer令牌,但是我仍然坚持正确的解析方法。 ...
php python parsing lexical-analysis ply
1个回答
0
投票
要解析具有任意数量的点的变量,我们可以使用如下所示的递归定义:

expression : VARIABLE | VARIABLE DOT expression

© www.soinside.com 2019 - 2024. All rights reserved.