парсинг — Создание лексических токенов для PHP с PLY

Я строю лексер PHP с использованием PLY, чтобы я мог понять концепции лексирования / разбора. Я решил начать с очень простого блока кода PHP:

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

В конечном итоге моя цель будет проанализировать это, чтобы я мог «отследить» ввод пользователя и убедиться, что он действительно попал в htmlspecialchars функция (или любую другую функцию, которую я выберу). Но прежде чем приступить к разбору, мне нужно правильно сгенерировать токены.

Я специально застрял на токенизации следующей строки:

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

Как лучше всего конвертировать все в токены? Мой текущий код распознает $msg в качестве переменной = как правильный токен, но остальная часть линии "Hello, " . $name . "!" рассматривается как один токен, который является неправильным.

Я очень новичок в этом болезненном мире лексизма / разбора, поэтому любая помощь будет принята с благодарностью. Вот мой текущий код и результаты:

import ply.lex as lex

states = (
)delimeters = ('LPAREN', 'RPAREN', 'LBRACKET', 'RBRACKET')

tokens = delimeters + (
"CHAR",
"NUM",
"OPEN_TAG",
"CLOSE_TAG",
"php",
"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 tdef 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_QUOTE(t):
r'"'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))string = """<?php if (isset($_REQUEST['name'])){
$name = $_REQUEST['name'];
$msg = "Hello, " . $name . "!";
$encoded = htmlspecialchars($msg);
}
?>"""
lex.lex()

lex.input(string)
for tok in iter(lex.token, None):
print repr(tok.type), repr(tok.value)

РЕЗУЛЬТАТЫ:

'OPEN_TAG' '<?php '
'CHAR' 'i'
'CHAR' 'f'
'LPAREN' '('
'CHAR' 'i'
'CHAR' 's'
'CHAR' 's'
'CHAR' 'e'
'CHAR' 't'
'LPAREN' '('
'VARIABLE' '$_REQUEST'
'LBRACKET' '['
'CONSTANT_ENCAPSED_STRING' "'name'"'RBRACKET' ']'
'RPAREN' ')'
'RPAREN' ')'
'LCURLYBRACKET' '{'
'VARIABLE' '$name'
'EQUALS' '='
'VARIABLE' '$_REQUEST'
'LBRACKET' '['
'CONSTANT_ENCAPSED_STRING' "'name'"'RBRACKET' ']'
'SEMICOLON' ';'
'VARIABLE' '$msg'
'EQUALS' '='
'QUOTED_ENCAPSED_STRING' '"Hello, " . $name . "!"'
'SEMICOLON' ';'
'VARIABLE' '$encoded'
'EQUALS' '='
'CHAR' 'h'
'CHAR' 't'
'CHAR' 'm'
'CHAR' 'l'
'CHAR' 's'
'CHAR' 'p'
'CHAR' 'e'
'CHAR' 'c'
'CHAR' 'i'
'CHAR' 'a'
'CHAR' 'l'
'CHAR' 'c'
'CHAR' 'h'
'CHAR' 'a'
'CHAR' 'r'
'CHAR' 's'
'LPAREN' '('
'VARIABLE' '$msg'
'RPAREN' ')'
'SEMICOLON' ';'
'RCURLYBRACKET' '}'
'CLOSE_TAG' '?>'

Таким образом, все токены кажутся правильными, за исключением QUOTED_ENCAPSED_STRING знак, но я не знаю, как это исправить. Это где «государства» пригодятся?

Конкретные вопросы:

  1. Как я могу это исправить, чтобы токены были правильно назначены?

  2. Как правильно назначить токен имени функции / метода? Например, в приведенном выше выводе вы видите, что htmlspecialchars а также isset функции просто обрабатываются как набор отдельных символов, но в конце концов, когда я приступлю к анализу, я захочу, чтобы мои токены были такими, чтобы распознавать имена функций было «легко».

1

Решение

Оказывается, в моем регулярном выражении была опечатка, которая и вызывала проблему.

обновление t_QUOUTED_ENCAPSED_STRING Следующее позволило приложению разбить каждый элемент на собственный токен:

def t_QUOTED_ENCAPSED_STRING(t):
r"\"([^\\"]|\\(.|\n))*\""t.lexer.lineno += t.value.count("\n")
return t

Теперь я запускаю приложение и получаю следующий вывод:

'OPEN_TAG' '<?php '
'CHAR' 'i'
'CHAR' 'f'
'LPAREN' '('
'CHAR' 'i'
'CHAR' 's'
'CHAR' 's'
'CHAR' 'e'
'CHAR' 't'
'LPAREN' '('
'VARIABLE' '$_REQUEST'
'LBRACKET' '['
'CONSTANT_ENCAPSED_STRING' "'name'"'RBRACKET' ']'
'RPAREN' ')'
'RPAREN' ')'
'LCURLYBRACKET' '{'
'VARIABLE' '$name'
'EQUALS' '='
'VARIABLE' '$_REQUEST'
'LBRACKET' '['
'CONSTANT_ENCAPSED_STRING' "'name'"'RBRACKET' ']'
'SEMICOLON' ';'
'VARIABLE' '$msg'
'EQUALS' '='
'QUOTED_ENCAPSED_STRING' '"Hello, "'
'DOT' '.'
'VARIABLE' '$name'
'DOT' '.'
'QUOTED_ENCAPSED_STRING' '"!"'
'SEMICOLON' ';'
'VARIABLE' '$encoded'
'EQUALS' '='
'CHAR' 'h'
'CHAR' 't'
'CHAR' 'm'
'CHAR' 'l'
'CHAR' 's'
'CHAR' 'p'
'CHAR' 'e'
'CHAR' 'c'
'CHAR' 'i'
'CHAR' 'a'
'CHAR' 'l'
'CHAR' 'c'
'CHAR' 'h'
'CHAR' 'a'
'CHAR' 'r'
'CHAR' 's'
'LPAREN' '('
'VARIABLE' '$msg'
'RPAREN' ')'
'SEMICOLON' ';'
'RCURLYBRACKET' '}'
'CLOSE_TAG' '?>'
0

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

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

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