PLY存储完整功能块



我想解析一些C文件,并提取有关已定义函数的所有信息(参数列表、函数块和函数类型(。在我的方法中,我试图将参数列表和功能块保存在特定的lex令牌中。为此,我使用了一个条件lexer。我想参数列表的方法很简单。每次找到左括号时,我都会启动条件状态。然后我计算所有附加的左括号和右括号。如果这个计数器再次达到零,我会获取第一个左括号的位置和最后一个左括号,并将信息存储在特定的lex标记中。

def t_parameter_rparen(t):
r')'
t.lexer.paren_level -= 1
if t.lexer.paren_level == 0:
t.value = t.lexer.lexdata[t.lexer.parameter_start:t.lexer.lexpos - 1]
t.type = 'PARAMETERLIST'
t.lexer.begin('INITIAL')
return t

我为功能块条件选择了相同的程序,但我的问题来了:

在我的一个C代码文件中,有一些预处理器指令,它们确实扰乱了代码结构。一个例子:

#ifdef SECURITY_STORAGE_MANAGER
#ifdef FALLBACK_MODE
void DecodeFile(uint8* Address, uint32 Length, bool zeroize)
#else
void DecodeFile(uint8* Address, uint32 Length)
#endif
{
uint32 Crc = 0;
uint8* Buffer = Address
#else
#ifdef FALLBACK_MODE
void DecodeFile(bool zeroize)
#else
void DecodeFile(void)
#endif
{
uint32 Crc = 0;
uint8* Buffer = Address
#endif
here starts the (common) function block
}

此示例显示,从左大括号到右大括号的数量不均匀。当我开始特定的条件并等待偶数个大括号时,我遇到了EOF问题。我永远无法停止条件并保存这个大括号构造的内容,所以我遇到的所有内容都是错误标记。下一个问题是,如果我想在那之后解析另一个文件,我的lexer仍然是坏的。之后我将提供我的代码示例。

据我所知,这个lexer没有处理预处理器指令的选项(否则,我可能需要向前看,确定它是否是一个已使用的定义,关于这一点,可能只需跳过#ifdef的内容。另一方面,我不知道如何用yacc处理一个完整的功能块。也许你们中有人知道我该怎么解决这个问题。

import ply.lex as lex
import ply.yacc as yacc
states = (
('function', 'exclusive'),
('parameter', 'exclusive'),
)
reserved = {
'void': 'VOID',
'int': 'INT',
'uint8': 'UINT8',
'uint16': 'UINT16',
'bool': 'BOOL',
}
tokens = [
'STRING',
'LBRACE',
'RBRACE',
'LPAREN',
'RPAREN',
'SEMICOLON',
'NUMERIC',
'LBRACKET',
'RBRACKET',
'PARAMETERLIST',
'ARGUMENTS',
] + list(reserved.values())
t_ignore = '\ t-."§$%&!=,*:+<>|?';[]_-,;#!'
t_parameter_ignore = '\ t#/-."§$%&!=,*:+<>|?'[];_-#!'
t_function_ignore = '\ t#/-."§$%&!=,*:+<>|?'();_-,[]'
# Start of token description for INITIAL state
t_LBRACE = r'{'
t_RBRACE = r'}'
t_LPAREN = r'('
t_RPAREN = r')'
# def t_HASH(t):
#     r'#'
#     pass

def t_STRING(t):
r'[a-zA-Z_][a-zA-Z_0-9]*'
t.type = reserved.get(t.value, 'STRING')
return t

def t_NUMERIC(t):
r'd+'
return t

# Start of token description for parameter list lexing state

def t_parameter(t):
r'('
t.lexer.parameter_list_start = t.lexer.lexpos
t.lexer.paren_level = 1
t.lexer.push_state('parameter')

def t_parameter_lparen(t):
r'('
t.lexer.paren_level += 1

def t_parameter_rparen(t):
r')'
t.lexer.paren_level -= 1
if t.lexer.paren_level == 0:
t.value = t.lexer.lexdata[t.lexer.parameter_list_start:t.lexer.lexpos - 1]
t.type = 'PARAMETERLIST'
t.lexer.pop_state()
return t

def t_parameter_STRING(t):
r'[a-zA-Z_][a-zA-Z_0-9]*'
t.type = 'STRING'
pass

def t_parameter_NUMERIC(t):
r'd+'
t.type = 'NUMERIC'
pass

# Start of token description for function block lexing state

def t_function(t):
r'{'
t.lexer.function_block_start = t.lexer.lexpos
t.lexer.brace_level = 1
t.lexer.push_state('function')

def t_function_lbrace(t):
r'{'
t.lexer.brace_level += 1

def t_function_rbrace(t):
r'}'
t.lexer.brace_level -= 1
if t.lexer.brace_level == 0:
t.value = t.lexer.lexdata[t.lexer.function_block_start:t.lexer.lexpos - 1]
t.type = 'FUNCTIONBLOCK'
t.lexer.pop_state()
return t

def t_function_STRING(t):
r'[a-zA-Z_][a-zA-Z_0-9]*'
t.type = 'STRING'
return t

def t_function_NUMERIC(t):
r'd+'
t.type = 'NUMERIC'
pass

# Start of token description valid for all states

def t_ANY_newline(t):
r'n+'
t.lexer.lineno += len(t.value)

def t_ANY_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)

def t_ANY_comment(t):
r'(/*(.|n)*?*/)|(//.*)'
pass

def t_ANY_ignore_comments(t):
r'//.*'
pass

lexer = lex.lex()
test_string = '''
#ifdef SECURITY_STORAGE_MANAGER
#ifdef FALLBACK_MODE
void DecodeFile(uint8* Address, uint32 Length, bool zeroize)
#else
void DecodeFile(uint8* Address, uint32 Length)
#endif
{
uint32 Crc = 0;
uint8* Buffer = Address
#else
#ifdef FALLBACK_MODE
void DecodeFile(bool zeroize)
#else
void DecodeFile(void)
#endif
{
uint32 Crc = 0;
uint8* Buffer = Address
#endif
here starts the (common) function block
}
'''
lexer.input(test_string)
for tok in lexer:
print(tok)

好的,我选择了gcc来预处理我的代码文件。我使用的命令:gcc -save-temps -E -c -o <outputfile.i> <inputfile.c>

在此之前,我创建了一个原始文件的副本,在那里我删除了所有的#includes,这样我就不必担心提供所有的libs等等

现在一切似乎都很顺利。

最新更新