【问题标题】:Parsing function arguments without arguments delimiters解析没有参数分隔符的函数参数
【发布时间】:2019-05-21 08:47:58
【问题描述】:

我正在做一个项目,我需要将 NetLogo 翻译成另一种编程语言。我正在使用 Boost Spirit,并且我已经实现了一些将简单代码语法存储到 AST 中的项目语法。

我面临的问题是,现在我无法判断标识符是变量名还是函数名。另外,我不知道一个特定的函数调用是否需要一个、两个或多个参数,所以我不知道何时停止寻找更多参数。

例如,函数调用可能看起来像

id1 id2 id3 id4

可能是:

  • id3 是一个以id4 作为参数的函数(假设它的返回值为id5),而id1 是一个以id2 和id5 作为参数的函数

但也可能是:

  • id1 有 id2 id3 id4 作为参数(除了 id1 之外的都是变量名)

我考虑过在每次声明变量或函数时使用符号并添加新项目,这将有助于区分变量名和函数名,但是......

  • 如何/应该如何使用 Boost Spirit 存储函数所需的参数数量?也许在解析函数定义时使用另一个带有语义操作的符号表?
  • 一旦我知道如何获取所需参数的数量,我如何在解析表达式时找到函数标识符后获取该值?
  • 使用符号来区分变量名和函数名是一个很好的解决方案吗?

【问题讨论】:

  • 看看编译器如何将源代码编译成机器码可能会有所帮助。以下是 C 编译器所做工作的一个非常基本的概要: 1st) 句法分析。将代码拆分为标记,例如“int 无效();” -> "int"、"void"、"("、")"、";" 2nd)检查此语法是否正确。例如"int void(;" 将不正确 3) 将函数或变量的每个声明写入带有类型信息的符号表中 4) 在语义分析中(这是您的问题所在)您检查的语义你的程序是正确的。例如int test = std::string { "test" };
  • 如果我没记错的话,步骤 1 和 2 由 Spirit 语法处理。然后,第三步是我要问的两个问题之一,所以我想去那个符号表是最好的方法吗?第 4 步是我不知道如何处理的一步(至少是函数参数部分)。
  • 重新思考你所说的,我认为我的问题不在第 4 步,而在第 2 步。我不知道如何解析函数调用,因为我没有任何标记分隔参数开始和结束的位置
  • 为什么这个问题被标记为 C++ 甚至 Boost.Spirit?两者都没有。
  • 因为我正在使用 Boost Spirit 开发解析器,并且我正在寻找一些关于如何处理它的建议,以及那些库。我会更新我的问题以更好地反映这一点。

标签: compiler-construction boost-spirit


【解决方案1】:

最后我做了如下:

  • 创建了一个符号表,使用函数名作为键,参数的数量作为存储的数据。
qi::symbols<char, int> f_args;
  • 在函数解析器上使用语义操作来获取函数名称和参数列表,并将其发送到外部函数以将数据存储在符号表中。
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) ];
  • 当在函数定义之外找到函数名称(即是函数调用)时,我会加载存储在符号表中的数据以在重复指令上使用它,并期望函数需要的确切参数数量。
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 | '_' | '-')]];

这个答案唯一没有回答的问题是最后一个问题。希望在这方面有更多经验的人能解释一下。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-24
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 2023-02-24
    相关资源
    最近更新 更多