1

我正在为一个名为 Compilers 的类制作一种自定义语言作为项目。整个项目是用 Java 编写的,使用JFlex作为我的词法分析器,并使用Cup作为我的句法分析器。

我为该语言创建了一个简单的文本编辑器,它基本上由一个 JTextPane 组成,用户可以在其中键入将被解析的自定义代码。这个JTextPane 有一个DefaultStyledDocument,用于设置字符属性,例如为JTextPane 中的代码(文本)更改关键字、注释、字符串、数字等的颜色。

这是我正在使用的代码:

        DefaultStyledDocument doc = new DefaultStyledDocument() {
        @Override
        public void insertString(int offset, String str, AttributeSet a) throws BadLocationException { //cuando se insertan caracteres.
            super.insertString(offset, str, a);
            String text = getText(0, getLength());
            syntax = new SyntaxHighlighter(new java.io.StringReader(text));
            Token val;
            try {
                while ((val = syntax.yylex()) != null) {
                    switch (val.type) {
                        case TokenType.KEYWORD:
                            setCharacterAttributes(val.start, val.length, keyword, true);
                            break;
                        case TokenType.COMMENT:
                            setCharacterAttributes(val.start, val.length, comment, true);
                            break;
                        case TokenType.STRING:
                            setCharacterAttributes(val.start, val.length, string, true);
                            break;
                        case TokenType.FUNCTION:
                            setCharacterAttributes(val.start, val.length, function, true);
                            break;
                        case TokenType.NUMBER:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                        case TokenType.OPERATOR:
                            setCharacterAttributes(val.start, val.length, operator, true);
                            break;
                        case TokenType.READ:
                            setCharacterAttributes(val.start, val.length, number, true);
                            break;
                        default:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                    }
                }
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(rootPane, "Oops! Exception triggered\n" + ex.getMessage());
            }
        }

        @Override
        //this is the method I want to optimize
        public void remove(int offs, int len) throws BadLocationException { 
            super.remove(offs, len);
            String text = getText(0, getLength());
            syntax = new SyntaxHighlighter(new java.io.StringReader(text));
            Token val;
            try {
                while ((val = syntax.yylex()) != null) {
                    switch (val.type) {
                        case TokenType.KEYWORD:
                            setCharacterAttributes(val.start, val.length, keyword, true);
                            break;
                        case TokenType.COMMENT:
                            setCharacterAttributes(val.start, val.length, comment, true);
                            break;
                        case TokenType.STRING:
                            setCharacterAttributes(val.start, val.length, string, true);
                            break;
                        case TokenType.FUNCTION:
                            setCharacterAttributes(val.start, val.length, function, true);
                            break;
                        case TokenType.NUMBER:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                        case TokenType.OPERATOR:
                            setCharacterAttributes(val.start, val.length, operator, true);
                            break;
                        case TokenType.READ:
                            setCharacterAttributes(val.start, val.length, number, true);
                            break;
                        default:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                    }
                }
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(rootPane, "Oops! Exception triggered\n" + ex.getMessage());
            }
        }
    };

this.codeTextPane.setStyledDocument(doc);

SyntaxHighlighter 类基本上是一个词法分析器(使用 JFlex 制作),仅用作搜索特定文本片段(关键字、字符串等)的一种方式。一切都很完美,但是...

问题:

当 JTextPane 中有大量文本时,按住退格键删除文本会使程序非常难以滞后。我认为发生这种情况的原因可能是因为 SyntaxHighlighter 运行时会删除每个字符,因为按住退格键会为每个被删除的字符调用 remove() 函数。插入文本实际上不是问题,因为您可以从文件中加载代码(该文件中的整个文本将由 SyntaxHighlighter 整体分析),或者您无法快速输入以注意到滞后。

有没有办法可以优化这个?谢谢你们!

4

3 回答 3

1

我的第一直觉是采用窗口策略。在您的代码中维护一棵树或其他能够表示自包含范围的结构。然后调整语法荧光笔和代码的其他部分,使其仅在他们知道受影响的树的部分(或其他)上工作。

抽象地说,你可能有这样的关系:

class
  |
+----------+
method1    method2
              |
           +--------+--------+
           line1    line2    line3

...这允许在不改变的情况下理解第 3 行中的删除

于 2015-05-12T15:36:41.837 回答
0

总而言之,这些代码似乎结构清晰,我很快就理解了。所以我的建议是:尽量保持原样(强制开闭原则)。

我建议的唯一更改是将字符删除与突出显示分开。这已经提到了。但是您应该这样做的原因是:您将能够延迟语法突出显示,直到用户删除了一大块字符。因此,每次仅删除一个字符时都不会触发语法突出显示。

我认为您应该将正文分解为句法单元,然后仅在更改的句法单元上应用语法突出显示。主要问题是改变单元的解析和识别。

正如前面的作者所提到的,将语法高亮隔离到一个单独的线程中也会提高性能。

这些变化不是微不足道的,而是可能的。

于 2015-05-12T15:42:31.820 回答
0

定义类字段javax.swing.Timer syntaxTimer

在每个insert()remove()检查是否syntaxTimer为空。

如果它为空,则创建syntaxTimer具有 500 毫秒延迟的实例(可以是 300 或 1000,如您所愿)并启动syntaxTimer. 如果不只是跳过计时器初始化,因为您已经初始化了它。

当调用syntaxTimer's时actionPerformed(),执行您的SyntaxHighlighter相关逻辑并清除syntaxTimer(停止并设置syntaxTimer=null)。

于 2015-05-14T06:17:10.413 回答