【问题标题】:Give instructions to the Java parser/lexer向 Java 解析器/词法分析器提供指令
【发布时间】:2011-02-23 00:21:22
【问题描述】:

有没有办法从java代码层面直接给解析器和lexar指令?如果不是,那怎么可能做到这一点呢?

问题是我想让解析器评估一个变量,备份,然后将该变量的值分配为对象名称。像这样:

String s = "text";

SomeClass (s) = new SomeClass();

解析器读取--> 好的,s 评估为“文本”... 解析器回溯,同时将“text”保存在内存中,并将“text”指定为 SomeClass 的新实例的名称,因此现在可以这样做:

text.callSomeMethod();

我需要这样做,因为我必须实例化任意数量的 SomeClass 对象。每个人都必须有一个唯一的名称,最好是这样做:

while (someArbitrarySet.hasNext()) {
    String s = "token" + Math.random();
    SomeClass (s) = new SomeClass();
    (s).callSomeMethod();
}

我希望这是有道理的......

【问题讨论】:

  • “每个人都必须有一个唯一的名称”——你真的是说每个人都必须绑定到源文本中的唯一标识符吗?为什么不把它们放在一个 Map 中,以“名称”为键呢?或者将名称设为 SomeClass 的字段?我认为你不需要你要求的重型火炮。
  • 我的意思是:SomeClass s; SomeClass q;某类 p; s、q 和 p 都必须不同。我被告知只需将它们放在地图中,但这需要创建大量对象,其中许多对象可能永远不需要。虽然这并不总是一个问题,但我正在使用非常处理能力/磁盘 + RAM 受限的机器。
  • 您要解决什么问题?也许有更好的选择。
  • 在不涉及太多细节的情况下,我正在编写一个在更大程序中运行的应用程序。通常,在我处理完这些对象后,它们会被垃圾收集,但是更大的程序会维护它们,因此需要为每个对象指定一个唯一的名称。如果我不给每个对象一个唯一的名称,旧对象将被覆盖,但在更大的程序的上下文中仍然需要它。
  • 我认为真正的问题是:为什么你认为你需要这样做?

标签: java parsing lexer


【解决方案1】:

您要求的是某些语言所称的 MACROS。它们有时也称为预处理器定义,或简称为“定义”。

决定在 Java 中不包含包含和宏等,因为它引入了额外的代码维护问题,设计人员认为这会导致代码不符合他们想要的样式。

但是,仅仅因为它没有内置到编译器中并不意味着您不能将它添加到您的构建脚本中。

作为构建的一部分,您将所有文件复制到 src-comp 目录,然后按照定义替换令牌。

我不建议这样做,但这并不意味着不可能。

【讨论】:

  • 这是评论,不是答案。
  • 不,这是一个答案。有两个问题。首先是它可以在Java代码级别完成。答案是否定的,因为设计师忽略了它。第二个是如果不是怎么做。答案是使用您自己的预处理脚本。我认为它很好地回答了这两个问题。当然里面有我的个人评论,但这是本网站不可或缺的一部分,它借鉴了其他人的经验。
  • 我会调查一下,谢谢。我曾尝试过几次 ant,但缺乏阅读所有内容的动力。蚂蚁可以帮忙吗?如果是这样,这可能是足够的动力。
  • 我可以看到蚂蚁这样做是的。 Ant 任务可以涵盖文件移动和进行转换的(perl?bash?java?)例程。如果您是 Java 开发人员,Ant 是一个有用的资源。
  • 自己的预处理脚本仍然不允许像在问题循环中那样在运行时创建新变量。
【解决方案2】:

您所描述的(在运行时创建新的命名变量)在 JavaScript、Lua、Bash 等解释型语言中是可能的,但在 Java 等编译型语言中则不然。循环执行时,没有源代码可操作,所有命名变量都必须先定义。

除此之外,您的变量不需要“唯一”名称,如果您按顺序(一个接一个)使用它们,您也可以像这样编写循环:

while (someArbitrarySet.hasNext()) {
    SomeClass sC = new SomeClass();
    sC.callSomeMethod();
}

如果您确实同时需要您的对象,请将它们放入某种数据结构中。最简单的是一个数组,如果你想通过键再次找到它们,你可以使用 Collection(如 ArrayList)或 Map(如 CajunLuke 所写)。

实际上,数组(在 Java 中)只不过是变量的集合(所有类型都相同),您可以通过 int 对其进行索引。

(并且允许在运行时创建新变量的脚本语言也使用某种映射字符串→(任何东西)来实现这一点,其中该映射是方法/脚本本地或属于某个周围对象。)


您在问题的评论中写道(最好将这些内容添加到问题本身,它有一个“编辑”按钮):

在不涉及太多细节的情况下,我正在编写一个在更大程序中运行的应用程序。通常,在我处理完这些对象后,它们会被垃圾收集,但是更大的程序会维护它们,因此需要为每个对象指定一个唯一的名称。如果我不给每个对象一个唯一的名称,旧对象将被覆盖,但在更大程序的上下文中仍然需要它。

那么,您想保留对象以避免垃圾回收吗?使用数组(或 List 或其他任何东西)。

问题是,如果您希望您的更大的程序能够使用这些对象,无论如何您都必须将它们交给这个更大的程序。然后这个程序必须保留对这些对象的引用,从而避免垃圾收集。所以看起来你想通过不存在的方式解决一个不存在的问题:-)

【讨论】:

  • 您关于“不使用像 Java 这样的编译语言”的声明意味着您不能在 C 或 C++ 等其他编译语言中执行此操作,而实际上您可以使用宏来执行此操作。当然,您没有将它们定义为字符串,但它们是他正在寻找的简单文本替换。
  • @glowcoder:看起来他想在运行时创建新变量,而不是在编译时(因为他实际上是在混合两者)。
  • @Paulo 感谢您的澄清!
  • @Paulo,我也说了没有过多的细节。程序会在创建这些对象时自动抓取它们。我肯定会在短期内使用 HashMap 或 ArrayList 左右。我将研究构建脚本解决方案作为长期修复。这部分是因为无论如何我真的需要学习使用 Ant。我最终可能会也可能不会坚持使用 HashMap/List 解决方案。也许我应该改变我接受的答案?很难选择接受哪一个,因为我将尝试同时使用这两个。
  • 嗯,你在这里做了一些奇怪的魔法......无论如何,在 java 中创建新的局部变量不是正确的方法(因为它在 VM 的运行时是不可能的,即使使用宏或不同的基于 JVM 的语言。您最多可以使用其他语法结构隐藏某些数据结构的使用。)
【解决方案3】:

不是您所提问题的真正答案,而是您问题的可能解决方案:使用地图。

Map variables = new HashMap();
while (someArbitrarySet.hasNext()) {
    String s = "token" + Math.random();
    variables.put(s, new SomeClass());
    variables.get(s).callSomeMethod();
}

这样,您可以使用“变量名”作为映射的键,并且您可以在不弄乱词法分析器/解析器的情况下顺利进行。

我真的希望有一种方法可以专门执行您在 Java 中声明的内容 - 这真的很酷。

【讨论】:

  • -1 这不会很酷。它被故意排除在语言之外,因为设计师不想要它。
  • @glowcoder “因为设计师”我认为他们也是那些迫使您一直使用类并且没有使函数成为一流的那些人?
  • @mathepic 就是他们。尝试维护一个超过 300 万行的应用程序,其中包含无处不在且没有合并功能。这是一场噩梦(即使它确实让我有工作:D)。
  • @glowcoder 我并不是在争论缺少宏是好事还是坏事,只是“设计师这样做”不足以成为它的理由不好。
  • @mathepic 这将是一个分歧点,但我相信这是它被认为是不好的一个原因,至少在 Java 领域(这个问题所在。) /跨度>
【解决方案4】:

没有。那是不可能的。

即使你可以,我也想不出调用它们的方法,因为不会有可以成功引用它们的编译代码。

所以这些选项是 CanjuLuke 描述的选项,或者创建自己的 java 解析器,可能使用 ANTRL sample Java grammar 并在此处挂钩您需要的内容。

考虑地图解决方案。

【讨论】:

    【解决方案5】:

    How do you use Java 1.6 Annotation Processing to perform compile time weaving? 已回答。

    总之,有一个注解处理工具可以让你扩展java语法,创建编译成java注解的DSL。

    在 JDK 1.5 下,您必须使用 apt 而不是 javac,但在 1.6 下,这些会受到 -processor 标志到 javac 的影响。来自javac -help

    -processor <class1>[<class2>,<class3>...]Names of the annotation processors to run; bypasses default discovery process
    -processorpath <path>      Specify where to find annotation processors
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-14
      • 2011-03-12
      • 2013-01-31
      • 1970-01-01
      • 2014-04-21
      • 1970-01-01
      • 1970-01-01
      • 2011-04-07
      相关资源
      最近更新 更多