如何捕获 JavaScript 中的 antlr 解析器或词法分析器错误?

问题描述 投票:0回答:1

所以我想制作一个名为 NLweb 的自定义前端框架,它是一些基本的东西,只有变量、函数和嵌套 jsx。

现在我想在我的编译函数中处理解析或词法分析错误(或在我的访问者中,但我想这是不可能的,因为在进入我的自定义访问者之前会抛出解析/词法错误)... 那么谁能告诉我如何捕获这些类型的错误?

  console.error
    line 3:4 missing ';' at '<EOF>'

      203 |
      204 |             this.state = 38;
    > 205 |             this.match(NLwebParser.T__2);
          |                  ^
      206 |         } catch (re) {
      207 |             if(re instanceof antlr4.error.RecognitionException) {
      208 |                     localctx.exception = re;

      at ConsoleErrorListener.syntaxError (node_modules/antlr4/src/antlr4/error/ErrorListener.js:44:17)
      at node_modules/antlr4/src/antlr4/error/ErrorListener.js:65:35
          at Array.map (<anonymous>)
      at ProxyErrorListener.syntaxError (node_modules/antlr4/src/antlr4/error/ErrorListener.js:65:24)
      at NLwebParser.notifyErrorListeners (node_modules/antlr4/src/antlr4/Parser.js:356:12)
      at DefaultErrorStrategy.reportMissingToken (node_modules/antlr4/src/antlr4/error/ErrorStrategy.js:375:20)
      at DefaultErrorStrategy.singleTokenInsertion (node_modules/antlr4/src/antlr4/error/ErrorStrategy.js:472:18)
      at DefaultErrorStrategy.recoverInline (node_modules/antlr4/src/antlr4/error/ErrorStrategy.js:438:18)
      at NLwebParser.match (node_modules/antlr4/src/antlr4/Parser.js:120:25)
      at NLwebParser.match [as variable] (src/js/generated/NLwebParser.js:205:15)
      at NLwebParser.variable [as statement] (src/js/generated/NLwebParser.js:142:19)
      at NLwebParser.statement [as compilation] (src/js/generated/NLwebParser.js:111:19)
      at compilation (src/js/index.js:18:32)
      at Object.<anonymous> (test/index.test.js:11:32)

这是一些背景:

我的语法:

grammar NLweb;

compilation
    : statement*
    ;

statement
    :   variable
    |   procedure
    |   callProcedure
    |   jsxTag
    ;

variable
    :   'waarde' Identifier '='? (literal)? ';'
    ;


literal
    :   Number
    |   String
    |   Check
    ;

procedure
    :   'procedure' Identifier '=>' parameters? '=>' '(' statement* ');'
    ;


parameters
    :   Identifier (',' Identifier)*
    ;

callProcedure
    :   'start' Identifier '=>' '(' parameters? ');'
    ;

jsxTag
    :   '<' Identifier '>' (text|jsxTag)* '</' Identifier '>'
    ;

text
    :   ~('\r' | '\n' | '<' | '>' )+
    ;

Identifier: [a-zA-Z_] [a-zA-Z0-9_]*;
Number : [0-9]+;
String : [a-zA-Z]+;
Check : 'True' | 'False';
WS  :   [ \t\r\n]+ -> skip ;

我的index.js:


import * as antlr from 'antlr4'
import NLwebLexer from './generated/NLwebLexer.js'
import NLwebParser from './generated/NLwebParser.js'
import Visitor from './Visitor'


export function nlWebCompile(input) {
    try {
        const chars = new antlr.InputStream(input)
        const lexer = new NLwebLexer(chars)
        const tokens = new antlr.CommonTokenStream(lexer)
        const parser = new NLwebParser(tokens)
        const context = parser.compilation()
        const visitor = new Visitor()
        return visitor.visitCompilation(context)
    }catch (error){
        throw Error('Syntax error')
    }

}

几个测试之一(它仍然通过测试,但我之前提供的错误仍然显示在控制台中,我想这也不是一个好兆头?):

// Test to declare variables
test('visitor should return correct type and identifier when declaring a variable', () => {
    const input = `
    waarde testWaarde = 5
    `
    const result = nlWebCompile(input)
    expect(result[0].type).toBe('variable')
    expect(result[0].identifier).toBe('testWaarde')
    expect(result[0].literal.literal).toBe('5')
})

这是我的一些访客:

class MyVisitor extends NLwebVisitor {

    visitCompilation(ctx) {
        const statements = ctx.statement()
        const result = []
        for (const statement of statements) {
            result.push(this.visitStatement(statement))
        }
        return result
    }
    visitStatement(ctx) {
        if (ctx.variable()) {
            return this.visitVariable(ctx.variable())
        } else if (ctx.procedure()) {
            return this.visitProcedure(ctx.procedure())
        } else if (ctx.callProcedure()) {
            return this.visitCallProcedure(ctx.callProcedure())
        }else if (ctx.jsxTag()) {
            return this.visitJsxTag(ctx.jsxTag())
        }
    }
    visitVariable(ctx) {
        const identifier = ctx.Identifier().getText()
        const literal = ctx.literal() ? this.visitLiteral(ctx.literal()) : []
        return {
            type : 'variable',
            identifier,
            literal
        }
    }
}

如果我添加一个像这样的错误监听器:

export function nlWebCompile(input) {
    const chars = new antlr.InputStream(input)
    const lexer = new NLwebLexer(chars)
    const tokens = new antlr.CommonTokenStream(lexer)
    const parser = new NLwebParser(tokens)
    parser.buildParseTrees = true
    parser.removeErrorListeners()
    parser.addErrorListener({
        syntaxError: (recognizer, offendingSymbol, line, column, msg, err) => {
            console.error(`${offendingSymbol} line ${line}, col ${column}: ${msg}`)
        }
    })
    const context = parser.compilation()
    const visitor = new Bezoeker()
    return visitor.visitCompilation(context)
}

在这样做之前,我的前 5 个测试会成功,但是在添加 errorListner 之后,这种情况发生在控制台中,我可以捕获所有错误而不是仅捕获语法错误吗:

 FAIL  test/index.test.js
  ✓ visitor should return correct type and identifier when declaring a variable (10 ms)
  ✓ visitor should return correct type, identifier, parameters and statements when declaring a procedure (3 ms)
  ✓ visitor should return correct type, identifier, parameters when calling a procedure (2 ms)
  ✕ visitor should return correct type and identifier for JSX statement (4 ms)
  ✓ generator should return correct javascript code (1 ms)
  ✕ generator should return correct javascript code for functions (4 ms)

  ● visitor should return correct type and identifier for JSX statement

    TypeError: d.reportAttemptingFullContext is not a function

      478 |                     this.state = 92; 
      479 |                     this._errHandler.sync(this);
    > 480 |                     _alt = this._interp.adaptivePredict(this._input,10, this._ctx);
          |                                         ^
      481 |             } while ( _alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER );
      482 |         } catch (re) {
      483 |             if(re instanceof antlr4.error.RecognitionException) {

      at node_modules/antlr4/src/antlr4/error/ErrorListener.js:73:35
          at Array.map (<anonymous>)
      at ProxyErrorListener.reportAttemptingFullContext (node_modules/antlr4/src/antlr4/error/ErrorListener.js:73:24)
      at ParserATNSimulator.reportAttemptingFullContext (node_modules/antlr4/src/antlr4/atn/ParserATNSimulator.js:1688:52)
      at ParserATNSimulator.execATN (node_modules/antlr4/src/antlr4/atn/ParserATNSimulator.js:455:22)
      at ParserATNSimulator.adaptivePredict (node_modules/antlr4/src/antlr4/atn/ParserATNSimulator.js:344:30)
      at NLwebParser.adaptivePredict [as text] (src/compiler/js/generated/NLwebParser.js:480:31)
      at NLwebParser.text [as jsxTag] (src/compiler/js/generated/NLwebParser.js:416:27)
      at NLwebParser.jsxTag (src/compiler/js/generated/NLwebParser.js:420:27)
      at NLwebParser.jsxTag [as statement] (src/compiler/js/generated/NLwebParser.js:157:19)
      at NLwebParser.statement [as compilation] (src/compiler/js/generated/NLwebParser.js:111:19)
      at compilation (src/compiler/js/NLwebCompiler.js:23:28)
      at Object.<anonymous> (test/index.test.js:55:32)

我尝试了仍然存在于我的index.js 中的try catch 块。 我在访问编译函数中尝试了 try-catch 块,但控制台中仍然出现解析器错误。 我尝试实现一个自定义错误监听器,但我希望能够成功。

javascript frontend frameworks antlr
1个回答
0
投票

ANTLR 使用错误监听器将您的错误报告给任何想要了解这些错误的人。由代码来调用这些监听器。在 Lexington 和 Parsing 期间,ANTLR 将处理自己的异常并向附加的任何错误侦听器报告错误。当您的访问者运行时,异常处理尚未到位。但是,您的访问者可以使用相同的错误侦听器来记录您在访问时遇到的错误;只需在错误侦听器上调用适当的方法即可。

注意:一般来说,您需要谨慎使用异常。如果你只是在遇到错误时抛出异常并且有顶级的 try-catch,那么你遇到的第一个错误将中止你对树的访问,并且你不会报告任何后续错误。您可能会做得更好,只要在遇到错误时调用错误侦听器上的方法即可直接添加错误。 (并不是说异常总是错误的答案,而是您需要了解捕获异常并从中恢复的含义)

© www.soinside.com 2019 - 2024. All rights reserved.