我为一个非常简单的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令牌,但是我仍然坚持正确的解析方法。 ...
expression : VARIABLE
| VARIABLE DOT expression