使用PLY为PHP创建词法分析标记

使用PLY为PHP创建词法分析标记,php,parsing,lex,lexical-analysis,ply,Php,Parsing,Lex,Lexical Analysis,Ply,我正在使用PLY构建一个PHP词法分析器,以便理解词法分析/解析背后的概念。我决定从一个非常简单的PHP代码块开始: <?php if (isset($_REQUEST['name'])){ $name = $_REQUEST['name']; $msg = "Hello, " . $name . "!"; $encoded = htmlspecialchars($msg); } ?> 将所有东西转换成代币的最佳方式是什么?我的当前代码将

我正在使用PLY构建一个PHP词法分析器,以便理解词法分析/解析背后的概念。我决定从一个非常简单的PHP代码块开始:

<?php if (isset($_REQUEST['name'])){
    $name     = $_REQUEST['name'];
    $msg      = "Hello, " . $name . "!";
    $encoded  = htmlspecialchars($msg);
}
?>
将所有东西转换成代币的最佳方式是什么?我的当前代码将
$msg
识别为一个变量,
=
识别为正确的标记,但行
的其余部分“Hello,”$名称“!”
被视为一个不正确的令牌

我对这个痛苦的词法分析/解析的世界非常陌生,因此任何帮助都将不胜感激。以下是我当前的代码和结果:

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 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_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)
将ply.lex导入为lex
国家=(
)
delimeters=('LPAREN','rpare','LBRACKET','RBRACKET')
代币=delimeters+(
“CHAR”,
“NUM”,
“打开标签”,
“关闭标签”,
“php”,
“变量”,
“常数\u装箱\u字符串”,
“装箱和空白”,
“带引号的包裹字符串”,
“lcurlyblacket”,
“RCURLYBRAKET”,
“平等”,
“分号”,
“引用”,
“点”,
“如果”
)
t\u ignore=“\t”
t_CHAR=r“[a-z]”
t_LPAREN=r'\('
t_rpare=r'\)'
t\u RBRACKET=r'\]'
t_LBRACKET=r'\['
t\u RCURLYBRACKET=r'\}
t\u LCURLYBRACKET=r'\{'
t_等于r'='
t_分号=r';'
t_点=r'\.'
def t_新线(t):
r'\n+'
t、 lexer.lineno+=t.value.count(“\n”)
def t_常量_封装_字符串(t):
r“'([^\\']\\\(.|\n))*”
t、 lexer.lineno+=t.value.count(“\n”)
返回t
def t_带引号的包裹字符串(t):
r“\”([^\\']\\\(.| \n))*\“”
t、 lexer.lineno+=t.value.count(“\n”)
返回t
def t_打开_标签(t):
r'\r?\n?“
t、 lexer.lineno+=t.value.count(“\n”)
#t、 lexer.begin('首字母')
返回t
def t_变量(t):
r'\$[A-Za-z\][\w\]*'
返回t
定义t_报价(t):
r''
定义t_NUM(t):
r“\d+”
t、 value=int(t.value)
返回t
def t_错误(t):
打印t.lexer.current_状态
打印目录(t.lexer)
raise TypeError(“未知字符'%s'”(t.value))
字符串=“”
lex.lex()
lex.input(字符串)
对于iter中的tok(lex.token,无):
打印报告(tok.type),报告(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' '?>'

“OPEN_TAG”事实证明,我的正则表达式中有一个输入错误导致了这个问题

t_quoted_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' '?>'

“OPEN_TAG”事实证明,我的正则表达式中有一个输入错误导致了这个问题

t_quoted_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' '?>'
“打开标签”