Antlr 编写模板语言/维文引擎

Antlr 编写模板语言/维文引擎,antlr,abstract-syntax-tree,viewengine,Antlr,Abstract Syntax Tree,Viewengine,除了完成任何真正的工作,我还有一个渴望。我最渴望的是编写一个视图引擎,它可以从另一种语言(TemplateToolkit/Perl)中模仿模板系统。如果我有时间/努力学习一些新的项目,这就是其中之一 我花了很多时间研究了CoCo/R和ANTLR,说实话,这让我的大脑很痛,但一些CoCo/R正在下沉。不幸的是,大多数示例都是关于创建一个可以读取源代码的编译器的,但似乎没有一个示例涉及如何为模板创建处理器 是的,这些都是相同的事情,但是我不知道如何定义模板的语言,其中大部分源代码是html,而不是正

除了完成任何真正的工作,我还有一个渴望。我最渴望的是编写一个视图引擎,它可以从另一种语言(TemplateToolkit/Perl)中模仿模板系统。如果我有时间/努力学习一些新的项目,这就是其中之一

我花了很多时间研究了CoCo/R和ANTLR,说实话,这让我的大脑很痛,但一些CoCo/R正在下沉。不幸的是,大多数示例都是关于创建一个可以读取源代码的编译器的,但似乎没有一个示例涉及如何为模板创建处理器

是的,这些都是相同的事情,但是我不知道如何定义模板的语言,其中大部分源代码是html,而不是正在解析和运行的实际代码

对于这类事情,有什么好的初学者资源吗?我在Spark上吃了一点甘纳,它在回购协议中似乎没有语法

也许这太过分了,可以在文件中用c#测试并编译模板语法


如果你处在我的位置,不是语言创建专家,你会从哪里开始?

步骤1。使用正则表达式(regexp替换)将输入模板字符串拆分为标记列表,例如,拆分

hel<b>lo[if foo]bar is [bar].[else]baz[end]world</b>!
hello[if foo]bar是[bar].[else]baz[end]世界!

write('hello')
如果('foo')
写入('bar is')
替换('bar')
写入('.'))
else()
写('baz')
完()
写(“世界!”)
第二步。将令牌列表转换为语法树:

* Sequence
** Write
*** ('hel<b>lo')
** If
*** ('foo')
*** Sequence
**** Write
***** ('bar is')
**** Substitute
***** ('bar')
**** Write
***** ('.')
*** Write
**** ('baz')
** Write
*** ('world</b>!')

class Instruction {
}
class Write : Instruction {
  string text;
}
class Substitute : Instruction {
  string varname;
}
class Sequence : Instruction {
  Instruction[] items;
}
class If : Instruction {
  string condition;
  Instruction then;
  Instruction else;
}
*序列
**写
***(“你好”)
**如果
***(‘foo’)
***序列
****写
*****(“酒吧是”)
****替代品
*****(“酒吧”)
****写
***** ('.')
***写
****(‘baz’)
**写
***(“世界!”)
课堂教学{
}
课堂写作:教学{
字符串文本;
}
课堂代课:教学{
字符串varname;
}
课程顺序:指令{
说明[]项;
}
类If:指令{
字符串条件;
指示;
其他指令;
}
第三步。编写一个递归函数(称为解释器),它可以遍历树并在树上执行指令


如果您的语言支持eval()(如Perl、Python、Ruby),另一种替代方法(而不是步骤1-3):使用regexp替换将模板转换为宿主语言中支持eval()的字符串,然后运行eval()实例化模板。

步骤1。使用正则表达式(regexp替换)将输入模板字符串拆分为标记列表,例如,拆分

hel<b>lo[if foo]bar is [bar].[else]baz[end]world</b>!
hello[if foo]bar是[bar].[else]baz[end]世界!

write('hello')
如果('foo')
写入('bar is')
替换('bar')
写入('.'))
else()
写('baz')
完()
写(“世界!”)
第二步。将令牌列表转换为语法树:

* Sequence
** Write
*** ('hel<b>lo')
** If
*** ('foo')
*** Sequence
**** Write
***** ('bar is')
**** Substitute
***** ('bar')
**** Write
***** ('.')
*** Write
**** ('baz')
** Write
*** ('world</b>!')

class Instruction {
}
class Write : Instruction {
  string text;
}
class Substitute : Instruction {
  string varname;
}
class Sequence : Instruction {
  Instruction[] items;
}
class If : Instruction {
  string condition;
  Instruction then;
  Instruction else;
}
*序列
**写
***(“你好”)
**如果
***(‘foo’)
***序列
****写
*****(“酒吧是”)
****替代品
*****(“酒吧”)
****写
***** ('.')
***写
****(‘baz’)
**写
***(“世界!”)
课堂教学{
}
课堂写作:教学{
字符串文本;
}
课堂代课:教学{
字符串varname;
}
课程顺序:指令{
说明[]项;
}
类If:指令{
字符串条件;
指示;
其他指令;
}
第三步。编写一个递归函数(称为解释器),它可以遍历树并在树上执行指令


如果您的语言支持eval()(如Perl、Python、Ruby),另一种替代方法(而不是步骤1-3):使用regexp替换将模板转换为宿主语言中支持eval()的字符串,然后运行eval()要实例化模板。

Spark语法是用一种流利的领域特定语言实现的

它是在几个层中声明的。识别html语法的规则在中声明-这些规则基于直接从xml规范复制的语法规则

标记规则引用在中声明的csharp语法规则的有限子集-这些是一个子集,因为Spark只需要识别足够的csharp来将字符串周围的单引号调整为双引号,匹配大括号等

单个规则本身属于接受a并返回a的类型。ParseResult是一个简单的类,其中包含由操作解析的TValue数据项和一个新的Position实例,该实例已超越生成TValue的内容

这本身并不是很有用,除非您引入一个,如中所述,它可以结合单个解析操作来构建关于不同语法构造的形状的非常详细和健壮的表达式

使用委托作为解析操作的技术来自Luke H的博客文章。我还写了一篇关于


如果愿意,也完全可以引用Spark.dll程序集并从base CharGrammar继承一个类,从而为特定语法创建一个全新的语法。这可能是开始试验这种技术的最快方法,可以在中找到一个例子。

Spark语法是用一种流利的领域特定语言实现的

它是在几个层中声明的。识别html语法的规则在中声明-这些规则基于直接从xml规范复制的语法规则

标记规则引用在中声明的csharp语法规则的有限子集-这些是一个子集,因为Spark只需要识别足够的csharp来将字符串周围的单引号调整为双引号,匹配大括号等

单个规则本身属于接受a并返回a的类型。ParseResult是一个简单的类,其中包含由操作解析的TValue数据项和一个新的Position实例,该实例已超越生成TValue的内容

这本身并不是很有用,除非您引入一个,如中所述,它可以结合单个解析操作来构建关于shap的非常详细和健壮的表达式