- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试从 C++ 迁移一个 antlr 项目。语法和代码生成大部分已完成(基于 65038949 中提供的解决方案),但一个悬而未决的项目是在 go 中编写自定义错误报告器。
我正在为这些目的寻找自定义错误报告程序:
我想打印我的自定义消息,可能带有额外信息(例如文件名,默认错误打印机不打印)。
对于每个错误,错误报告器都会更新一个全局计数器,并且在主程序中如果此错误计数>0,则将跳过进一步的处理。
所以这是在 c++ 项目中完成的工作:
在此函数中定义了一条自定义消息:
string MyErrorMessage(unsigned int l, unsigned int p, string m) {
stringstream s;
s << "ERR: line " << l << "::" << p << " " << m;
global->errors++;
return s.str();
}
并且 antlr 运行时 (ConsoleErrorListener.cpp
) 已更新为调用上述函数:
void ConsoleErrorListener::syntaxError(IRecognizer *, Token * ,
size_t line, size_t charPositionInLine, const std::string &msg, std::exception_ptr) {
std::cerr << MyErrorMessage(line, charPositionInLine, msg) << std::endl;
}
最后,主程序会像这样跳过进一步的处理:
parser.top_rule();
if(global->errors > 0) {
exit(0);
}
如何为antlr的go target重写这些c++代码?
浏览 antlr 运行时代码(来自 github.com/antlr/antlr4/runtime/Go/antlr)后的一些附加说明:
parser.go 有一个变量“_SyntaxErrors”,它会在每次错误时递增,但似乎没有人使用它。这个变量的用途是什么,解析后如何使用它来检查是否发生了任何错误?我做了以下,但显然那没有用! (解决方法是在解析器中添加一个新变量 MyErrorCount,并在 _SyntaxErrors 也递增时递增它,但这看起来不像是一个优雅的解决方案,因为我在这里编辑运行时代码!)
tree := parser.Top_rule() // this is ok
fmt.Printf("errors=%d\n", parser._SyntaxErrors) // this gives a compiler error
//fmt.Printf("errors=%d\n", parser.MyErrorCount) // this is ok
在上面的注释中,我在 antlr 代码中引入了一个新变量,并在用户代码中读取它 - 糟糕的编码风格,但有效。但我还需要做相反的事情——antlr 错误报告器 (error_listener.go:SyntaxError()) 需要读取具有文件名的用户代码变量并打印它。我可以通过在 antlr 中添加一个新函数来传递这个参数并将这个文件名注册到一个新变量中来做到这一点,但是有没有更好的方法来做到这一点?
最佳答案
Antlr 很棒,但是,需要注意的一点是,在错误处理方面,它不是 Go 惯用的语言。这使得整个错误过程对于 GoLang 工程师来说是不直观的。
为了在每个步骤(词法分析、解析、遍历)中注入(inject)您自己的错误处理,您必须注入(inject)带有 panic 的错误监听器/处理程序。 Panic & recovery 非常像 Java 异常,我认为这就是它被设计成这样的原因(Antlr 是用 Java 编写的)。
您可以根据需要实现任意数量的 ErrorListener。默认使用的是 ConsoleErrorListenerInstance
.它所做的只是在 SyntaxErrors 上打印到 stderr ,所以我们删除它。自定义错误报告的第一步是替换它。我做了一个基本的,它只收集自定义类型中的错误,我可以稍后使用/报告。
type CustomSyntaxError struct {
line, column int
msg string
}
type CustomErrorListener struct {
*antlr.DefaultErrorListener // Embed default which ensures we fit the interface
Errors []error
}
func (c *CustomErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
c.Errors = append(c.Errors, &CustomSyntaxError{
line: line,
column: column,
msg: msg,
})
}
您可以在解析器/词法分析器上注入(inject)错误监听器(同时清除默认监听器)。
lexerErrors := &CustomErrorListener{}
lexer := NewMyLexer(is)
lexer.RemoveErrorListeners()
lexer.AddErrorListener(lexerErrors)
parserErrors := &CustomErrorListener{}
parser := NewMyParser(stream)
p.removeErrorListeners()
p.AddErrorListener(parserErrors)
当 Lexing/Parsing 完成时,两个数据结构都会有在 Lexing/Parsing 阶段发现的语法错误。您可以尝试使用 SyntaxError
中给出的字段。您必须在别处寻找其他接口(interface)函数,例如 ReportAmbuiguity
。
if len(lexerErrors.Errors) > 0 {
fmt.Printf("Lexer %d errors found\n", len(lexerErrors.Errors))
for _, e := range lexerErrors.Errors {
fmt.Println("\t", e.Error())
}
}
if len(parserErrors.Errors) > 0 {
fmt.Printf("Parser %d errors found\n", len(parserErrors.Errors))
for _, e := range parserErrors.Errors {
fmt.Println("\t", e.Error())
}
}
警告:这真的感觉很糟糕。如果只需要错误收集,只需执行上面显示的操作即可!
要中途中止 lex/parse,您必须在错误监听器中引发 panic 。老实说,我不明白这种设计,但词法分析/解析代码包含在 panic recover 中,检查 panic 是否属于 RecognitionException
类型。此异常作为参数传递给您的 ErrorListener
,因此请修改 SyntaxError
表达式
func (c *CustomErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
// ...
panic(e) // Feel free to only panic on certain conditions. This stops parsing/lexing
}
这个 panic 错误被捕获并传递给实现 ErrorStrategy
的 ErrorHandler
.我们关心的重要函数是Recover()
。 Recover 尝试从错误中恢复,消耗 token 流,直到可以找到预期的模式/ token 。由于我们希望它中止,我们可以从 BailErrorStrategy
中汲取灵感。 .这个策略仍然很糟糕,因为它使用 panic 来停止所有工作。您可以简单地省略实现。
type BetterBailErrorStrategy struct {
*antlr.DefaultErrorStrategy
}
var _ antlr.ErrorStrategy = &BetterBailErrorStrategy{}
func NewBetterBailErrorStrategy() *BetterBailErrorStrategy {
b := new(BetterBailErrorStrategy)
b.DefaultErrorStrategy = antlr.NewDefaultErrorStrategy()
return b
}
func (b *BetterBailErrorStrategy) ReportError(recognizer antlr.Parser, e antlr.RecognitionException) {
// pass, do nothing
}
func (b *BetterBailErrorStrategy) Recover(recognizer antlr.Parser, e antlr.RecognitionException) {
// pass, do nothing
}
// Make sure we don't attempt to recover from problems in subrules.//
func (b *BetterBailErrorStrategy) Sync(recognizer antlr.Parser) {
// pass, do nothing
}
然后加入解析器
parser.SetErrorHandler(NewBetterBailErrorStrategy())
话虽这么说,我建议只收集听众的错误,而不是费心尝试提前中止。 BailErrorStrategy
似乎并不是那么好用,使用 panics 来恢复在 GoLang 中感觉很笨拙,很容易搞砸。
关于go - 如何在 antlr 的 go target 中编写自定义错误报告器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66067549/
我之前让 dll 注入(inject)器变得简单,但我有 Windows 7,我用 C# 和 C++ 做了它,它工作得很好!但是现在当我在 Windows 8 中尝试相同的代码时,它似乎没有以正确的方
我正在尝试制作一个名为 core-splitter 的元素,该元素在 1.0 中已弃用,因为它在我们的项目中起着关键作用。 如果您不知道 core-splitter 的作用,我可以提供一个简短的描述。
我有几个不同的蜘蛛,想一次运行所有它们。基于 this和 this ,我可以在同一个进程中运行多个蜘蛛。但是,我不知道如何设计一个信号系统来在所有蜘蛛都完成后停止 react 器。 我试过了: cra
有没有办法在达到特定条件时停止扭曲 react 器。例如,如果一个变量被设置为某个值,那么 react 器应该停止吗? 最佳答案 理想情况下,您不会将变量设置为一个值并停止 react 器,而是调用
https://code.angularjs.org/1.0.0rc9/angular-1.0.0rc9.js 上面的链接定义了外部js文件,我不知道Angular-1.0.0rc9.js的注入(in
我正在尝试运行一个函数并将服务注入(inject)其中。我认为这可以使用 $injector 轻松完成.所以我尝试了以下(简化示例): angular.injector().invoke( [ "$q
在 google Guice 中,我可以使用函数 createInjector 创建基于多个模块的注入(inject)器。 因为我使用 GWT.create 在 GoogleGin 中实例化注入(in
我在 ASP.NET Core 1.1 解决方案中使用配置绑定(bind)。基本上,我在“ConfigureServices Startup”部分中有一些用于绑定(bind)的简单代码,如下所示: s
我在 Spring MVC 中设置 initBinder 时遇到一些问题。我有一个 ModelAttribute,它有一个有时会显示的字段。 public class Model { privat
我正在尝试通过jquery post发布knockoutjs View 模型 var $form = $('#barcodeTemplate form'); var data = ko.toJS(vm
如何为包含多态对象集合的复杂模型编写自定义模型绑定(bind)程序? 我有下一个模型结构: public class CustomAttributeValueViewModel { publi
您好,我正在尝试实现我在 this article 中找到的扩展方法对于简单的注入(inject)器,因为它不支持开箱即用的特定构造函数的注册。 根据这篇文章,我需要用一个假的委托(delegate)
你好,我想自动注册我的依赖项。 我现在拥有的是: public interface IRepository where T : class public interface IFolderReposi
我正在使用 Jasmine 测试一些 Angular.js 代码。为此,我需要一个 Angular 注入(inject)器: var injector = angular.injector(['ng'
我正在使用 Matlab 代码生成器。不可能包含代码风格指南。这就是为什么我正在寻找一个工具来“ reshape ”、重命名和重新格式化生成的代码,根据我的: 功能横幅约定 文件横幅约定 命名约定 等
这个问题在这里已经有了答案: Where and why do I have to put the "template" and "typename" keywords? (8 个答案) 关闭 8
我开发了一种工具,可以更改某些程序的外观。为此,我需要在某些进程中注入(inject)一个 dll。 现在我基本上使用这个 approach .问题通常是人们无法注入(inject) dll,因为他们
我想使用 swing、spring 和 hibernate 编写一个 java 应用程序。 我想使用数据绑定(bind)器用 bean 的值填充 gui,并且我还希望它反射(reflect) gui
我有这段代码,当两个蜘蛛完成后,程序仍在运行。 #!C:\Python27\python.exe from twisted.internet import reactor from scrapy.cr
要点是 Spring Batch (v2) 测试框架具有带有 @Autowired 注释的 JobLauncherTestUtils.setJob。我们的测试套件有多个 Job 类提供者。因为这个类不
我是一名优秀的程序员,十分优秀!