C3语言定义(EBNF方言)关键字: Section Class End Scanner Parser Rule Label Letter Digit LetterOrDigit UpperLetter LowerLetter Symbol WhiteSpace CrLf
操作符: => , + * [] ! |
其它字符: () ;其中
Section,
Class,
End,
Rule,
Label为EBNF语言通用关键字。Label只允许使用一个终结符作为推导。Scanner,Parser作为特殊关键字,表示扫描器和分析器的规则。Letter等为Scanner规则专用关键字,它将对应于其字面意义的字符类型。 => 为推导符,表示前面的规则是由后面的产生式推导出来的。不允许出现在推导表达式中。; 为推导结束符号,类似于c中的逻辑行结束符。, 为连接符,也可以使用空白。+ 为正闭包,后置运算符,表示其前面的元素的正整数次幂是可接受的。* 星闭包,后置运算符,表示其前面的元素的自然数次幂是可接受的。[] 可选,表示其中的元素可以匹配也可以不匹配。() 括号,处理优先级问题。! 非,后置运算符,扫描器规则专用。并且只允许单个字符或其或操作进行非操作。| 或,表示可以匹配多个元素中的一个。 其中*,+,!为一元运算符。连接和或为二元运算符。优先级为!>*=+>连接>或 区别Unicode字符与普通字符。 由于实现问题,扫描器的规则使用Label型的字符串表示的.NET正则表达式。而不是标准的EBNF语言的语义。主要是转换上的技术问题。
示例代码:1. ID=>Letter+; 上面的例子是说标签ID是由字符的正闭包组成的,即一个或多个字符组成。例如:a,aaaaa,Hello….都是合法的ID,而a2,__a__都是不合法的。
2. ID=>LetterOrDigit*; ID由字符或数字的星闭包,即0个或多个字符或数字组成。例如:φ,aa,sss,a3,a2都是合法的。
3. ID=>Letter!+; ID由不是字符的符号组成。例如:32-9023&*)是合法的,而234af是不合法的。
4. ID=>”Hello”; ID只有一个合法形式,即Hello,其他形式一概不合法。
5. ID=>”Hello”|”Hi”; ID只有两个合法形式,即Hello和Hi,其他形式一概不合法。
6. ID=>”aaa”[“sss”]”ddd”; ID可以匹配aaaddd也可以匹配aaasssddd,即sss是可选的。
注意事项: 不要把WhiteSpace关键字作为语句的开始,因为它不生成匹配代码。规则调用要放在终结符匹配之前。 这样,一个EBNF方言的基本结构已经渐渐呈现出来了。接下来我们使用C3来描述它自己。同时我们就可以看到C3的用法以及证明其可用性。
EBNF自描述:Class Scanner '这是必不可少的,否则没有扫描器,整个编译器都没法工作。 Section Operator '操作符段,标识所有的操作符,可以使用与VB类似的单词型的操作符。 Label Trans=>"=>"; '推导符,表示右边的表达式是左边的规则的推导。 Label EndLine=>";"; '由于有些规则非常长,以及出于代码的可读性的担心, '使用结束符来表示语句的结束,同时由于忽略空白的特性 '使其可以和C语言一样将语句分成多个行来书写以增强可读性。 Label Join=>","; '在初期的策划中,空白有意义,但在后继版本中,空白 '不再有意义,所以间隔两个单词就需要一个分隔符,由此保留。 Label Positive=>"+"; '正闭包 Label Repeat=>"*"; '星闭包 Label LOpt=>"["; '可选开始 Label ROpt=>"]"; '可选结束。可选符实际上有两个符号组成,由于也是括 '号所以也有分割/改变优先级的作用。 Label Not=>"!"; '非,只可用于扫描器的单字符或字符集。 End Section Section KeyWord '关键字段,将所有的关键字都放在这里。 Label K_Section=>"Section"; '用于声明区段 Label K_Class=>"Class"; '声明类,实际上目前的语法只有两个类,即Scanner和Parser Label K_End=>"End"; '结束区段或类 Label K_Scanner=>"Scanner"; ' Label K_Parser=>"Parser"; ' Label K_Rule=>"Rule"; '声明一个语法规则 Label K_Label=>"Label"; '声明一个字符串常量 Section Letters Label K_Letter=>"Letter"; Label K_Digit=>"Digit"; Label K_LOD=>"LetterOrDigit"; Label K_Upper=>"UpperLetter"; Label K_Lower=>"LowerLetter"; Label K_Symbol=>"Symbol"; Label K_WhiteSpace=>"WhiteSpace"; End Section Label K_CrLf=>"CrLf"; End Section Section Comment Label LineComment=>"'"; '注释 End Section Section Other '这个段的规则使用.NET的正则表达式而简化 '转换的复杂性 Rule ID=>("_"LetterOrDigit|Letter)("_"|LetterOrDigit)*; '"((_[\d\p{L}])|\p{L})[_\d\p{L}]*" Rule String=>""""(""""!|"""""")*""""; '"""([^""]|"""")*""" End Section End Class Class Parser Rule Program=>ScannerDecl ParserDecl; '扫描器类在前,分析器类在后。 Rule ScannerDecl=> "Class" "Scanner" [OperatorSection] [KeyWordSection] [CommentSection] [OtherRuleSection] "End" "Class"; Rule OperatorSection=> "Section" "Operator" SCSectionDecl* LabelDecl* "End" "Section"; Rule KeyWordSection=> "Section" "KeyWord" SCSectionDecl* LabelDecl* "End" "Section"; Rule CommentSection=> "Section" "Comment" [LineComDecl] [BlockComStart '声明了开始符就必须声明结束符,否则将被忽略。 BlockComEnd] "End" "Section"; Rule OtherSection=> "Section" "Other" SCSectionDecl* LabelDecl* "End" "Section"; Rule LineComDecl=>"Rule" "LineComment" "=>" String; '注释符显然只能是一个字符串。 Rule BlockComStart=>"Rule" "BlockCommentStart" "=>" String; Rule BlockComEnd=>"Rule" "BlockCommentEnd" "=>" String; Rule SCSectionDecl=> "Section" ID (LabelDecl|SCRuleDecl)* "End" "Section"; Rule SCROSectionDecl=> '只允许声明规则的Section,这是上面的规范所要求的, '但是为了实现上的方便,实际上并没有使用。 "Section" ID SCRuleDecl* "End" "Section"; Rule LabelDecl=>"Label" ID "=>" String; Rule SCRuleDecl=>"Rule" ID "=>" SCExp; Rule SCQExp=>("(" SCExp ")")|("[" SCExp "]"); Rule SCExp=>SCOrExp["!"]["*"|"+"]; Rule SCOrExp=>SCJoinExp("|" SCJoinExp)*; Rule SCJoinExp=>SCExpElem([","] SCExpElem)*; Rule SCExpElem=>String|Letters|SCQExp; '下面的是分析器的 Rule ParserDecl=> "Class" "Parser" (SectionDecl |RuleDecl)* "End" "Class"; Rule RuleDecl=>"Rule" ID "=>" Exp; Rule QExp=>("(" Exp ")")|("[" Exp "]"); Rule Exp=>OrExp["!"]["*"|"+"]; Rule OrExp=>JoinExp("|" JoinExp)*; Rule JoinExp=>ExpElem([","] ExpElem)*; Rule ExpElem=>String|ID|QExp; Rule SectionDecl=> "Section" ID (LabelDecl|RuleDecl)* "End" "Section"; Rule ROSectionDecl=>'只允许声明规则的Section "Section" ID RuleDecl* "End" "Section"; End Class 给出上面的EBNF自描述的目的在于既可以使人更深入的了解C3的目的、格式、含义、语法。接下来我们要着手实现这个C3的编译器。
本文地址:http://com.8s8s.com/it/it41162.htm