解析没有参数定界符的函数参数
Parsing function arguments without arguments delimiters
我正在做一个项目,我需要将 NetLogo 翻译成另一种编程语言。我正在使用 Boost Spirit,我已经实现了一些将简单代码语法存储到 AST 中的项目语法。
我面临的问题是现在我无法判断标识符是变量名还是函数名。另外,我不知道一个特定的函数调用是否需要一个、两个或多个参数,所以我不知道什么时候停止寻找更多的参数。
例如,一个函数调用可以看起来像
id1 id2 id3 id4
那可能是:
id3
是一个以 id4
作为参数的函数(假设 return 的值为 id5
),而 id1
是一个以 id2
和 id5
作为参数的函数
但也可以是:
id1
有 id2
id3
id4
作为参数(除 id1
外都是变量名)
我考虑过使用 Symbols 并在每次声明变量或函数时添加新项,这将有助于区分变量名和函数名,但是...
- 如何 can/should 使用 Boost Spirit 存储函数所需的参数数量?也许在解析函数定义时使用另一个带有语义操作的符号 table?
- 一旦我知道如何获取所需参数的数量,在解析表达式时找到函数标识符后如何获取该值?
- 用Symbols来区分变量名和函数名是个好办法吗?
最后我做了以下事情:
- 创建了一个 Symbols table,使用函数名作为键,参数个数作为数据存储。
qi::symbols<char, int> f_args;
- 在函数解析器上使用语义操作获取函数名称和参数列表,并将其发送到外部函数以存储符号上的数据table。
void store_function (std::string name, std::list<std::string> args) {
f_args.add(name, args.size());
std::cout << name << " " << args.size() << std::endl;
}
function_ = (
lexeme[(string("to-report") | string("to")) >> !(alnum | '_')] // make sure we have whole words
> identifier
> ('[' > argument_list > ']')
> body
> lexeme[string("end") >> !(alnum | '_')]
) [ phx::bind(&store_function, _2, _3) ];
- 当在函数定义之外找到函数名称时(意味着这是一个函数调用),我加载存储在 Symbols Table 上的数据以在 repeat 指令上使用它并期望确切的数量函数需要的参数。
function_call =
function_name >>
repeat( phx::ref(n_args) )[identifier];
function_name =
!lexeme[keywords >> !(alnum | '_')] >>
&lexeme[f_args [phx::ref(n_args) = _1] >> !(alnum | '_')] >>
raw[lexeme[(alpha | '_') >> *(alnum | '_' | '-')]];
这个答案唯一没有回答的是最后一个问题。希望有这方面经验的人来解释一下。
我正在做一个项目,我需要将 NetLogo 翻译成另一种编程语言。我正在使用 Boost Spirit,我已经实现了一些将简单代码语法存储到 AST 中的项目语法。
我面临的问题是现在我无法判断标识符是变量名还是函数名。另外,我不知道一个特定的函数调用是否需要一个、两个或多个参数,所以我不知道什么时候停止寻找更多的参数。
例如,一个函数调用可以看起来像
id1 id2 id3 id4
那可能是:
id3
是一个以id4
作为参数的函数(假设 return 的值为id5
),而id1
是一个以id2
和id5
作为参数的函数
但也可以是:
id1
有id2
id3
id4
作为参数(除id1
外都是变量名)
我考虑过使用 Symbols 并在每次声明变量或函数时添加新项,这将有助于区分变量名和函数名,但是...
- 如何 can/should 使用 Boost Spirit 存储函数所需的参数数量?也许在解析函数定义时使用另一个带有语义操作的符号 table?
- 一旦我知道如何获取所需参数的数量,在解析表达式时找到函数标识符后如何获取该值?
- 用Symbols来区分变量名和函数名是个好办法吗?
最后我做了以下事情:
- 创建了一个 Symbols table,使用函数名作为键,参数个数作为数据存储。
qi::symbols<char, int> f_args;
- 在函数解析器上使用语义操作获取函数名称和参数列表,并将其发送到外部函数以存储符号上的数据table。
void store_function (std::string name, std::list<std::string> args) {
f_args.add(name, args.size());
std::cout << name << " " << args.size() << std::endl;
}
function_ = (
lexeme[(string("to-report") | string("to")) >> !(alnum | '_')] // make sure we have whole words
> identifier
> ('[' > argument_list > ']')
> body
> lexeme[string("end") >> !(alnum | '_')]
) [ phx::bind(&store_function, _2, _3) ];
- 当在函数定义之外找到函数名称时(意味着这是一个函数调用),我加载存储在 Symbols Table 上的数据以在 repeat 指令上使用它并期望确切的数量函数需要的参数。
function_call =
function_name >>
repeat( phx::ref(n_args) )[identifier];
function_name =
!lexeme[keywords >> !(alnum | '_')] >>
&lexeme[f_args [phx::ref(n_args) = _1] >> !(alnum | '_')] >>
raw[lexeme[(alpha | '_') >> *(alnum | '_' | '-')]];
这个答案唯一没有回答的是最后一个问题。希望有这方面经验的人来解释一下。