Правильная стратегия синтаксического анализа с использованием PLY.yacc

Я пишу синтаксический анализатор PHP на языке PLY, чтобы научить себя принципам лексизации / разбора.

У меня есть токены лексера, созданные для очень простого фрагмента кода PHP, но я застрял на правильном способе анализа.

Вот фрагмент кода, который я пытаюсь проанализировать:

  <?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)

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]