【问题标题】:JavaCC using input as a 'token'JavaCC 使用输入作为“令牌”
【发布时间】:2013-03-28 17:08:51
【问题描述】:

我已经为此困惑了好几天,搜索似乎没有给出任何结果。让我想知道这是否可能。例如:

funct functionNAME (Object o) { o+1 };

关键是用户必须在花括号内使用标识符“o”,而不是其他标识符。这当然是由 (Object o) 部分中的输入指定的,其中 'o' 可以是任何东西。基本上花括号内的标识符必须与参数中定义的标识符相同。我知道我可以存储匹配的标记并将其打印到屏幕上,但是否可以将其用作词法标记本身?谢谢。

【问题讨论】:

  • 你问的是反射吗? stackoverflow.com/questions/37628/…
  • 如果您正在使用 JavaCC 编写编译器,您要做的是维护一个符号表,以跟踪代码中每个点可以使用的标识符。符号表通常还保留有关标识符的其他有用信息,例如它们代表什么(例如变量与函数)以及它们的类型。
  • 你能澄清一下这个问题吗?我从您的最后一句话中得到的是:“我可以使用 [匹配的标记] 作为词汇标记吗?”但我怀疑这不是你的意思。
  • 您知道如何定义令牌,例如LETTER_A : {"a"} 或定义解析器可以通过令牌接受的内容,例如 | ,我想说的是解析器可以接受的内容取决于输入,这意味着它不是我事先设置的,例如USER_INPUT:{用户输入}。我想存储这个输入并像那样使用它。我不知道他们会放什么,除了它会是一个字符串,例如它可能是一个单一的 'y' 字符。清楚吗?我知道这是一个很奇怪的问题,因为我在任何地方都没有找到答案。

标签: java variables match token javacc


【解决方案1】:

是的,有更好的方法来做到这一点。你需要一个符号表。符号表的工作是跟踪程序中每个点可以使用哪些标识符。通常,符号表还包含有关标识符的其他信息,例如它们代表什么(例如变量或函数名称)以及它们的类型。

使用符号表,您可以检测到在解析许多语言(但不是全部)期间不在范围内的变量的使用。例如。 C 和 Pascal 是必须在使用标识符之前声明标识符的语言(有一些例外)。但是其他语言(例如Java)允许在使用标识符后声明标识符,在这种情况下,最好不要尝试检测错误,例如在程序被解析之前使用未声明的变量。 (确实在 Java 中,您需要等到所有文件都被解析,因为标识符可能会在另一个文件中声明。)

我假设一个简单的场景,就是你只需要记录变量的信息,没有类型信息,使用前必须声明。这会让你开始。我没有费心将函数名添加到符号表中。

假设一个符号表是一堆叫做帧的东西。每个帧都是一组可变的字符串。 (稍后您可能希望将其更改为从字符串到一些附加信息的可变映射。)

void Start(): { }
{
    <FUNCTION>
    <IDENTIFIER>
    {symttab.pushNewFrame() ;}
    <LBRACKET> Parameters()  <RBRACKET> 
    <LBRACE> Expression() <RBRACE>
    {symtab.popFrame() ; }
}
void Parameters() : {}
{
     ( Parameter() (<COMMA>   Parameter() )* )?
}
void Parameter() : {  Token x ; }
    <OBJECT> x=<IDENTIFIER>
    { if( symtab.topFrame().contains(x.image) ) reportError( ... ) ; }
    { symtab.topFrame().add(x.image) ; }
}
void Expression() : {  }
{
    Exp1() ( <PLUS> Exp1() )*
}
void Exp1() : { Token y ; }
{
    y = <IDENTIFIER>
    { if( ! symtab.topFrame().contains(y.image) ) reportError( ... ) ; }
|
    <NUMBER>
}

【讨论】:

  • 堆栈是最好的方法吗?
  • 这取决于您的编译器/语言处理器的性质。对于一次性编译器,您永远不需要在符号超出范围后访问它;在这种情况下,一堆帧是有意义的。例如,在您的语言中,在每个子例程结束时,不再需要参数,因此您可以将顶部帧从符号表堆栈中弹出。对于多遍编译器,符号表将在以后的遍中使用,因此将符号表框架保持在树结构中更有意义。
【解决方案2】:

你可以将标识符匹配的值存储在o中,然后在大括号中检查标识符是否相同,否则抛出异常。

【讨论】:

  • 是的,我知道这是可能的,但就我所知。然后我无法弄清楚如何将其用作“令牌”。例如: void showO(): {} { o.image } 我知道代码不起作用,但我正在寻找类似的东西。
【解决方案3】:

好的,我已经根据我在 OP 中给出的示例找到了一种方法来获得我想要的东西。这是我在我的解决方案中实现的一个简单变体,只是为了提供概念证明。为简单起见,将省略令牌定义等琐碎的事情。

void Start():
{
    Token x, y;
}
{
    <FUNCTION>
    <FUNCTION_NAME>
    <LBRACKET>
    <OBJECT>
    x = <PARAMETER>
    <RBRACKET>
    <LBRACE>
    y = <PARAMETER>
    {
        if (x.image.equals(y.image) == false)
        {
            System.out.println("Identifier must be specified in the parameters.");
            System.exit(0);
        }
    }
    <PLUS>
    <DIGIT>
    <RBRACE>
    <COLON>
}

有没有更好的方法来做到这一点?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 2014-07-21
    • 2018-06-18
    • 1970-01-01
    相关资源
    最近更新 更多