0

我有 9 种不同的语法。其中一个将根据它正在解析的文件的第一行 txt 的内容来加载。

我正在考虑将词法分析器/解析器派生到 sep. 类,然后在我得到匹配后立即实例化它们——但不确定这是否会减慢我的速度。我想一些基准测试是有序的。

真的,速度绝对是我的目标,但我知道这是丑陋的代码。

现在代码看起来像这样:

sin.mark(0)
site = findsite(txt)
sin.reset()

if ( site == "site1") {
   loadlexer1;
   loadparser1;
} else if (site == "site2") {
   loadlexer2;
   loadparser2;
}
.................
} else if (site == "site8") {
   loadparser8;
   loadparser8;
}

findsite(txt) {
  ...................
  if line.indexOf("site1-identifier") {
    site = site1;
  } else if(line.indexOf("site2-identifier") {
    site = site2;
  } else if(line.indexOf("site3-identifier") {
    site = site3;
  }
  .........................
  } else if(line.indexOf("site8-identifier") {
    site = site8;
  }
}

一些澄清

1) 是的,我确实有 9 种不同的语法,我用 antlr 构建,所以它们都有自己的词法分析器/解析器对象。

2) 是的,截至目前,我们正在比较字符串,显然它将被某种整数映射替换。我还考虑将站点标识符粘贴到一个正则表达式中,但是我不相信这会加快任何速度。

3)是的,这是伪代码,所以我不会对这里的语义过于挑剔..

4) kdgregory 指出我无法创建词法分析器/解析器对的一个实例是正确的

我喜欢散列的想法,让代码看起来更好看,但我不认为它会加快我的速度。

4

11 回答 11

7

标准方法是使用 Map 将键字符串连接到将处理它们的词法分析器:

Map<String,Lexer> lexerMap = new HashMap<String,Lexer>();
lexerMap.put("source1", new Lexer01());
lexerMap.put("source2", new Lexer02());
// and so on

检索到标识要使用的词法分析器的字符串后,您可以从 Map 中检索它,如下所示:

String grammarId = // read it from a file, whatever
Lexer myLexer = lexerMap.get(grammarId);

但是,您的示例代码有一些怪癖。首先, indexOf() 调用表明您没有独立的字符串,并且 Map 不会查看字符串内部。因此,您需要有某种方法从您读取的任何字符串中提取实际密钥。

其次,词法分析器和解析器通常会维护状态,因此您将无法创建单个实例并重用它。这表明您需要创建一个工厂类,并将其存储在映射中(这是抽象工厂模式)。

如果您希望有很多不同的词法分析器/解析器,那么使用映射驱动的方法是有意义的。对于少数人来说,if-else 链可能是您最好的选择,正确封装(这是工厂方法模式)。

于 2009-05-21T16:51:57.850 回答
2

使用多态性几乎可以保证比字符串操作更快,并且会在编译时检查其正确性。真的site是字符串吗?如果是这样,FindSite 应该被称为 GetSiteName。我希望 FindSite 返回一个Site知道适当词法分析器和解析器的对象。

另一个速度问题是编码速度。在单独的类中拥有不同的词法分析器和解析器肯定会更好(也许在另一个类中具有共享功能)。它会让你的代码稍微小一点,而且对别人来说更容易理解。

于 2009-05-21T16:42:03.177 回答
1

就像是:

Map<String,LexerParserTuple> lptmap = new HashMap<String,LexerParserTuple>();
lpt=lptmap.get(站点)
lpt.loadlexer()
lpt.loadparser()

结合一些正则表达式魔术而不是 string.indexOf() 来获取站点的名称应该可以显着清理您的代码。

于 2009-05-21T16:51:20.693 回答
1

用多态性替换条件

对于半成品,对于 findsite(),您可以简单地设置一个 HashMap 来让您从站点标识符到站点。另一种清理方法是简单地返回站点字符串,因此:

String findsite(txt) {
  ...................
  if line.indexOf("site1-identifier") 
    return site1;
  if(line.indexOf("site2-identifier")
    return  site2;
  if(line.indexOf("site3-identifier")
    return  site3;
...
}

以这种方式使用 indexOf() 并没有真正的表现力;我会使用 equals() 或 contains()。

于 2009-05-21T16:55:37.407 回答
1

我正在考虑将词法分析器/解析器派生到 sep. 类,然后在我得到匹配项后立即实例化它们

看起来你已经有了答案。这将创建更灵活但不需要更快的代码。

我想一些基准测试是为了

是的,使用这两种方法进行衡量并做出明智的决定。我的猜测是你已经拥有它的方式就足够了。

也许,如果让您烦恼的是有一个“公里”方法,您可以使用extract 方法在不同的函数中重构它。

最重要的是首先要有一个解决方案,即使它很慢也能完成这项工作,一旦你让它工作,分析它并检测可以提高性能的点。记住“优化规则”

于 2009-05-21T17:01:48.270 回答
1

假设您的代码效率低下。

实际解析输入所需的时间会超过(比如说)1% 的时间吗?

如果没有,你有更大的“炸鱼”。

于 2009-05-21T17:05:25.330 回答
0

我不了解 Java,但某些语言允许 switch 接受字符串。

switch(site)
{
    case "site1": loadlexer1; loadparser1; break;
    case "site2": loadlexer2; loadparser2; break;
    ...
}

至于秒位,使用正则表达式提取标识符并打开它。您最好使用enum.

于 2009-05-21T20:11:16.203 回答
0

我会更改 findsite 的类型以返回站点类型(超类),然后利用多态性...这应该比字符串操作更快...

你需要单独的词法分析器吗?

于 2009-05-21T16:52:47.257 回答
0

使用地图将站点配置为加载策略结构。然后需要根据“站点”进行简单查找,然后执行适当的策略。findSite() 也可以这样做。

于 2009-05-21T16:55:27.050 回答
0

可以有一个标识符与站点的映射,然后只需遍历映射条目。

// define this as a static somewhere ... build from a properties file
Map<String,String> m = new HashMap<String,String>(){{
    put("site1-identifier","site2");
    put("site2-identifier","site2");
}}

// in your method
for(Map.Entry<String,String> entry : m.entries()){
    if( line.contains(entry.getKey())){
        return line.getValue();
    }
}

清洁工:是 更快:不知道......应该足够快

于 2009-05-21T16:55:41.353 回答
0

你可以使用反射

char site = line.charAt(4);
Method lexerMethod = this.getClass().getMethod( "loadLexer" + site, *parameters types here*)
Method parserMethod = this.getClass().getMethod( "loadparser" + site, *parameters types here*)

lexerMethod.invoke(this, *parameters here*);
parserMethod.invoke(this, *parameters here*);
于 2009-05-21T16:55:56.550 回答