当前位置: 首页 > news >正文

网站建设技术及服务承诺怎么样从头开始做网站

网站建设技术及服务承诺,怎么样从头开始做网站,做网站怎么自定义背景图片,asp.net网站开发全过程用antlr解析简单的语法很简单 。 您要做的就是使用正则表达式描述您的语言#xff0c;并让antlr生成词法分析器和解析器。 解析大型或复杂的语言有时会需要更多#xff0c;因为仅使用正则表达式描述它们是困难的#xff0c;甚至是不可能的。 语义谓词是在语法内部编写的Jav… 用antlr解析简单的语法很简单 。 您要做的就是使用正则表达式描述您的语言并让antlr生成词法分析器和解析器。 解析大型或复杂的语言有时会需要更多因为仅使用正则表达式描述它们是困难的甚至是不可能的。 语义谓词是在语法内部编写的Java或C JavaScript或…条件。 Antlr使用它们在多个替代方案之间进行选择或者作为要检查的其他声明。 它们可以放在lexer和解析器中但是本文仅着重于它们在解析器中的用法。 它们为antlr增加了很多功能。 这篇文章假定您对什么是antlr以及生成的解析器如何工作有一般的了解。 如果您不这样做请先阅读链接的文章。 它们包含所需的一切。 第一章包含两个动机用例。 第二章介绍语法术语并显示简单的失败的语义谓词。 然后该帖子解释了语义谓词如何影响预测和生成的代码。 它还显示了如何编写有用的条件以及如何解决初始用例。 最后一章将其总结为简短的结论。 这篇文章中使用的所有示例和语法都可以在Github上找到 。 目录 用例 关键字–第n个 基本 句法 吊装和预测 这是什么 回溯 写作条件 输入令牌流 解决初始用例 关键字–第n个 包起来 验证语义谓词 资源资源 用例 当我们花一些时间解析类css的语言时 两个用例都描述了在编写该解析器的css部分时必须解决的问题。 第一个是在处理伪类时遇到的问题第二个是在选择器中处理棘手的空格。 如果您从未使用过CSS或对用例不感兴趣请跳过本章。 关键字–第n个 一些css 伪 类需要参数该参数可以是数字标识符选择器或称为nth表达式的参数。 仅在某些伪类内允许第N个表达式并且这些伪类的名称不是CSS中的保留关键字。 第N个表达式是形式为anb的表达式其中a和b是可选整数。 第n个有效表达式的示例 5n2 -5n-2 -5n -2 -n n 。 我们希望语法接受第n个表达式但仅将其作为实际允许使用的伪类的参数。 我们希望它拒绝第n个表达式作为所有其余伪类的参数。 所有名称通常对应于IDENT令牌。 创建与第n个伪类名称相对应的特殊标记是不切实际的因为它们不是保留关键字。 例如它们也是完全有效的类名称或元素名称。 拥有特殊令牌将迫使我们用IDENT | NTH替换几乎所有IDENT事件IDENT | NTH IDENT | NTH 。 因此我们剩下的通用标识符IDENT可以是普通或第n个伪类名称。 标准句法正则表达式无法区分它们但是语义谓词可以。 链接到解决方案。 重要空白 CSS具有半重要的空格。 半重要性意味着它们中的大多数仅表示令牌的结尾也就是它们的作用结束的地方。 例如声明中的空格是不相关的。 以下声明是相等的 padding : 2; padding:2; 大多数CSS语法的行为均与上述相同因此强烈倾向于将所有空格都丢弃。 但是如果这样做那么接下来的两个选择器将最终成为相同的IDENT COLON IDENT LPAREN COLON IDENT RPAREN COLON IDENT LPAREN COLON IDENT RPAREN LBRACE令牌流 div :not(:enabled) :not(:disabled) {} div:not(:enabled):not(:disabled) {} 选择器中的空格很重要。 第一个选择器等效于div *:not(:enabled) *:not(:disabled)而第二个选择器则不是。 注意 可从antlr网站获得的CSS 2.1语法忽略了此问题。 如果要使用它则必须先对其进行修复。 一种解决方案是停止隐藏空格。 这将迫使我们在所有解析器规则的所有可能位置中添加显式空白WS* 。 这将需要大量工作并且所产生的语法将难以理解。 也有可能放弃antlr解析器中的选择器树构建并为其编写定制的手工树构建器。 这是我们最初执行此操作的方式我们可以放心地说它可以工作但是比基于最终语义谓词的解决方案需要更多的时间和调试时间。 链接到解决方案。 基本 我们从语义谓词语法和一些需要的术语开始。 本章还概述了断言失败时的基本情况。 我们不会详细介绍这些将在下一章中进行介绍。 句法 语义谓词总是括在花括号内后跟问号或问号和双箭头 { condition }? { condition }? 第一个示例使用简单 123和235条件。 语法存储在Basics.g文件中 LETTER : a..z | A..Z; word: LETTER {123}? LETTER;NUMERAL: 0..9; number: {235}? NUMERAL NUMERAL; 术语 根据所使用的语法以及语法的位置语义谓词可以通过以下三种不同的名称之一进行调用 歧义语义谓词 验证语义谓词 门控语义谓词。 歧义语义谓词 消除歧义的谓词使用较短的{...}? 句法。 但是仅当谓词位于规则的开头或替代项的开头时才称为歧义消除。 歧义语义谓词 LETTER : a..z | A..Z; // beginning of a rule rule: {123}? LETTER LETTER;// beginning of an alternative alternatives: LETTER ({235}? LETTER*| {235}? LETTER ); 验证语义谓词 验证谓词还使用较短的{...}? 句法。 消除歧义谓词的区别仅在于位置。 验证谓词位于规则的中间或替代的中间 LETTER : a..z | A..Z; word: LETTER {123}? LETTER; 门控语义谓词 门控语义谓词使用更长的{...}?语法。 该条件可以放置在任何地方。 门控语义谓词 NUMERAL: 0..9; number: {235}? NUMERAL NUMERAL; 谓词失败 正如我们在表达式语言教程文章中所解释的那样解析器开始知道哪个规则应该对应于输入然后尝试将其与输入匹配。 匹配总是从规则的最左边的元素开始一直到右边。 如果匹配遇到语义谓词则它将测试条件是否满足。 如果不满意则抛出FailedPredicateException异常。 请考虑本章开头显示的Basics.g语法 LETTER : a..z | A..Z; word: LETTER {123}? LETTER;NUMERAL: 0..9; number: {235}? NUMERAL NUMERAL; 如果打开生成的BasicsParser类您会发现每个规则都有相同名称的对应方法。 它们都包含谓词的副本并且如果不满足条件它们都将引发异常 // inside the generated word() method if ( !((123)) ) {throw new FailedPredicateException(input, word, 123); } // inside the generated number() method if ( !((235)) ) {throw new FailedPredicateException(input, number, 235); } 预测例如如果解析器同时遇到带有多个备选和谓词的规则会发生什么情况 start: word | number start: word | number规则将在下一章中介绍。 吊装和预测 根据使用语义谓词的位置和方式解析器可能会尝试避免失败的谓词异常。 使用的策略称为“提升”这使谓词变得有用。 本章说明了什么是起重以及其产生的后果。 然后我们将说明何时使用和不使用它。 这是什么 遇到具有多个备选方案的规则的解析器必须决定应使用这些备选方案中的哪个。 如果其中一些以谓词开头则解析器可以使用该谓词来帮助决策。 考虑存储在DisambiguatingHoistingNeeded.g文件中的语法 LETTER : a..z | A..Z; word: {123}? LETTER LETTER; sameWord: {12!3}? LETTER LETTER;start: word | sameWord; 生成的解析器的word()和sameWord()方法都包含通常的失败谓词检查。 DisambiguatingHoistingNeededParser类摘录 //inside the word() method if ( !((123)) ) {throw new FailedPredicateException(input, word, 123); } //inside the sameWord() method if ( !((12!3)) ) {throw new FailedPredicateException(input, sameWord, 12!3); } 另外与start规则相对应的代码包含word和sameWord语义谓词的副本。 选择下一步使用哪个规则的部分包含以下代码注释是我的 int LA1_2 input.LA(3); //predicate copied from the word rule if ( ((123)) ) {alt11; } //predicate copied from the sameWord rule else if ( ((12!3)) ) {alt12; } else {NoViableAltException nvae new NoViableAltException(, 1, 2, input);throw nvae; } 将谓词复制到生成的解析器的预测部分中的操作称为提升。 后果 如果没有提升则谓词仅充当断言。 我们可以使用它们来验证某些条件仅此而已。 上面的语法是非法的–如果您忽略谓词它有两种语法上等效的替代方法。 由于提升的语法在整个语法中都占主导地位因此对它们也有一些局限性。 您可以放心地忽略不只是在后台发生的事情 每个谓词可以运行多次 谓词运行的顺序可能很难预测 本地变量或参数可能在悬挂式副本中不可用。 条件必须无副作用可重复且评估顺序无关紧要。 如果将它们提升为其他规则则它们将无法引用局部变量或参数。 只有放在规则开头的谓词才会被提升到其他规则中。 在其他情况下吊装仅在规则之内。 因此如果谓词未放在规则的开头则可以破坏第三条规则。 使用时 仅当解析器必须在多个规则或替代方法之间做出决定并且其中一些规则以谓词开头时才使用提升。 如果它是门控谓词例如{...}?语法中的条件则无论如何都将提升谓词。 如果它是消除歧义的谓词例如{...}?内的条件{...}? 语法则仅在确实需要谓词时才会挂起谓词。 术语“实际需要”是指多个备选方案可以匹配相同的输入。 否则仅当某些输入的多个替代项不明确时才使用它。 置于规则中间或替代中间的谓词永远不会被提升。 如果需要吊装-消除谓词歧义 考虑规则 start DisambiguatingHoistingNotNeeded.g语法start LETTER : a..z | A..Z; NUMBER : 0..9; word: {123}? LETTER LETTER; differentWord: {12!3}? LETTER NUMBER;start: word | differentWord; 规则 start必须在word规则和differentWord规则之间进行选择。 它们都以谓词开头但是不需要谓词来区分它们。 word的第二个标记是LETTER而differentWord的第二个标记是NUMBER 。 不会使用吊装。 相反语法将研究即将到来的2个标记以区分这些规则。 为了进行验证请在我们的示例项目中打开生成的DisambiguatingHoistingNotNeededParser类的start()方法既没有复制123也没有复制12!3条件。 int alt12; switch ( input.LA(1) ) { case LETTER: {switch ( input.LA(2) ) {case LETTER: {alt11;}break;case NUMBER: {alt12;}break;default:NoViableAltException nvae new NoViableAltException(, 1, 1, input);throw nvae; } 另一方面请考虑从DisambiguatingHoistingNeeded.g语法中start的规则 LETTER : a..z | A..Z; word: {123}? LETTER LETTER; sameWord: {12!3}? LETTER LETTER;start: word | sameWord; 规则start必须在word规则和sameWord规则之间进行选择。 这两个规则完全匹配相同的标记序列并且仅谓词不同。 将使用吊装。 要进行验证请在我们的示例项目中打开生成的DisambiguatingHoistingNeededParser类的start()方法。 它包含123和12!3条件的副本。 int alt12; switch ( input.LA(1) ) { case LETTER: {switch ( input.LA(2) ) {case LETTER: {int LA1_2 input.LA(3);if ( ((123)) ) {alt11;} else if ( ((12!3)) ) {alt12;} else { /* ... */ }}break;default: // ...} } break; default: // ... } 谓词中的歧义歧义正在发生完全相同的事情。 这将不会被吊起DisambiguatingHoistingNotNeeded.g语法 LETTER : a..z | A..Z; alternatives: LETTER ({235}? LETTER| {235}? NUMBER ); 这将被悬挂DeambiguatingHoistingNeeded.g语法 LETTER : a..z | A..Z; alternatives: LETTER ({235}? LETTER| {235}? LETTER ); 始终吊起–门控规则 查看GatedHoisting.g语法中的start规则 LETTER : a..z | A..Z; NUMBER: 0..9;word: {123}? LETTER LETTER; differentWord: {12!3}? LETTER NUMBER;start: word | differentWord; 规则start必须在word和differentWord单词之间进行选择。 它们都以谓词开头不需要谓词来区分它们。 但是将使用卷扬因为我们使用了门控语义谓词。 要进行验证请在我们的示例项目中打开生成的GatedHoisting类的start()方法。 它包含123和12!3条件的副本。 int LA1_0 input.LA(1);if ( (LA1_0LETTER) (((123)||(12!3)))) {int LA1_1 input.LA(2);if ( (LA1_1LETTER) ((123))) {alt11;}else if ( (LA1_1NUMBER) ((12!3))) {alt12;}else {NoViableAltException nvae new NoViableAltException(, 1, 1, input);throw nvae;} } else {NoViableAltException nvae new NoViableAltException(, 1, 0, input);throw nvae; } 在替代方案中门控谓词发生了完全相同的事情。 这将被提升GatedHoisting.g语法 LETTER : a..z | A..Z; NUMBER: 0..9;alternatives: LETTER ({235}? LETTER| {235}?NUMBER ); 永不吊装-一条规矩 如果谓词位于规则或替代规则的中间则永远不要使用提升。 使用哪种谓词类型都没有关系。 因此如果您的规则仅因谓词而不同则该谓词必须放在规则或替代规则的开头。 非提升的门控谓词GatedNoHoisting.g LETTER: a..z | A..Z; NUMBER: 0..9;//gated predicate in the middle of a rule word: LETTER {123}? LETTER; differentWord: LETTER {12!3}? NUMBER;start: word | differentWord; 另一个非悬挂式门控谓词GatedNoHoisting.g LETTER: a..z | A..Z; NUMBER: 0..9;//gated predicate in the middle of an alternative alternatives: LETTER (LETTER {235}? LETTER| LETTER {235}? NUMBER ); 生成的解析器在GatedNoHoistingParser类中。 最重要的一点是如果您的规则仅因谓词而不同并且该谓词位于规则的中间则antlr将拒绝生成相应的解析器。 下一个可扩展框包含语法错误的几个语法示例以及它们引起的反错误。 不正确的语法SyntacticallyIncorrect.g LETTER : a..z | A..Z; word: LETTER {123}? LETTER; sameWord: LETTER {12!3}? LETTER;start: word | sameWord; 控制台错误 warning(200): org\meri\antlr\predicates\SyntacticallyIncorrect.g:28:6: Decision can match input such as LETTER LETTER using multiple alternatives: 1, 2 As a result, alternative(s) 2 were disabled for that input error(201): org\meri\antlr\predicates\SyntacticallyIncorrect.g:28:6: The following alternatives can never be matched: 2 另一个不正确的语法SyntacticallyIncorrect.g alternativesStart: LETTER (LETTER {123}?| LETTER {12!3}? ); 控制台错误 warning(200): org\meri\antlr\predicates\SyntacticallyIncorrect.g:31:27: Decision can match input such as LETTER using multiple alternatives: 1, 2 As a result, alternative(s) 2 were disabled for that input error(201): org\meri\antlr\predicates\SyntacticallyIncorrect.g:31:27: The following alternatives can never be matched: 2 另一个不正确的语法SyntacticallyIncorrect.g LETTER : a..z | A..Z; gatedWord: LETTER {123}? LETTER; gatedSameWord: LETTER {12!3}? LETTER;gatedStart: gatedWord | gatedSameWord; 控制台错误 warning(200): org\meri\antlr\predicates\SyntacticallyIncorrect.g:40:11: Decision can match input such as LETTER LETTER using multiple alternatives: 1, 2 As a result, alternative(s) 2 were disabled for that input error(201): org\meri\antlr\predicates\SyntacticallyIncorrect.g:40:11: The following alternatives can never be matched: 2 上次不正确的语法SyntacticallyIncorrect.g LETTER : a..z | A..Z; gatedAlternativesStart: LETTER (LETTER {123}? LETTER| LETTER {12!3}? LETTER ); 控制台错误 warning(200): org\meri\antlr\predicates\SyntacticallyIncorrect.g:43:32: Decision can match input such as LETTER LETTER using multiple alternatives: 1, 2 As a result, alternative(s) 2 were disabled for that input error(201): org\meri\antlr\predicates\SyntacticallyIncorrect.g:43:32: The following alternatives can never be matched: 2 细微差别 上一章“何时使用”子章节显示了谓词在明显悬挂和明显不悬挂的情况下的行为。 我们选择了一些示例以显示尽可能简单明了的情况。 本子章节包含不同的示例集。 我们选择了我们所知道的最有可能引起混淆的地方。 所有使用的示例都位于Nuances.g文件中。 消除歧义谓词–高级 仅当多个替代方案对于当前输入不明确时才使用提升歧义的谓词。 否则仅当实际输入可以由多个替代方案解析时才运行谓词的提升后的副本。 示例以下规则中的替代项在语法上不等效因为它们与同一组输入不匹配。 第一个备选方案完全匹配两个字母第二个备选方案匹配任意数量的字母 advancedDisambiguating: LETTER ({123}? LETTER LETTER| {12!3}? LETTER* ); 如果输入正好以一个LETTER开头则第一个选择不能解析它。 因为只有第二个替代匹配所以不会使用谓词。 解析器将使用第二个替代方法如果12!3条件恰好为false 则解析器将引发失败的谓词异常。 但是如果输入以两个字母开头则两个选项都可以匹配它并且将使用谓词。 这是生成的代码的样子 int alt42; switch ( input.LA(1) ) { case LETTER: {switch ( input.LA(2) ) {case LETTER: {int LA4_3 input.LA(3);//predicate is used only if first two tokens are LETTERif ( ((123)) ) {alt41;}else if ( ((12!3)) ) {alt42;}else {// ... irrelevant code ... }}break;//if the second token is not LETTER, predicate is not usedcase EOF: { alt42; } break;default: // ... }}break; //if the first token is not LETTER, predicate is not used case EOF: // ... default: // ... } 将其与非常相似的门控规则进行比较 compareGated: LETTER ({123}? LETTER LETTER| {12!3}? LETTER* ); 解析器将不使用谓词。 永远不会输入第二个选择因为永远不会满足谓词12!3 int alt62; int LA6_0 input.LA(1);if ( (LA6_0LETTER) (((123)||(12!3)))) {int LA6_1 input.LA(2);if ( (LA6_1LETTER) (((123)||(12!3)))) {int LA6_3 input.LA(3); 在这种情况下门控谓词会使antlr引发不同类型的异常。 正如我们将在本文后面所展示的门控谓词和歧义谓词的不同提升对于更复杂的谓词而言可以带来更大的不同。 即它可以在接受和拒绝输入之间有所不同。 循环尽管乍看起来并不像循环但是循环也是替代方法。 他们使用预测来猜测是否应该再进行一轮还是应该结束。 仅在谓词返回true时才使用谓词 LETTER : a..z | A..Z; loop: ( {somePredicate()}? LETTER )*; loop规则将匹配字母直到函数somePredicate()返回false或直到规则用完LETTER令牌为止。 loop1: do {int alt12;int LA1_0 input.LA(1);// predicate is used during the predictionif ( (LA1_0LETTER) ((somePredicate()))) {alt11;}//matching: either jump out or match another LETTERswitch (alt1) {case 1: {if ( !((somePredicate())) ) {throw new FailedPredicateException(...);}// ... match LETTER ...}break;default:break loop1;} } while (true); 消除歧义的谓词不能用于此目的。 下一个谓词将不会用于决定解析器是否应留在循环中 LETTER : a..z | A..Z; loopDisambiguating: ( {somePredicate()}? LETTER )*; 从技术上讲循环由LETTER和nothing替代方案决定。 这些在语法上是不同的并且只有在必须在语法上模棱两可的替代方案之间做出决定时预测才使用歧义谓词。 loopDisambiguating规则将匹配字母直到用完LETTER令牌为止。 如果函数somePredicate()在此期间返回false 则该规则将引发FailedPredicateException异常。 生成的代码与前一个代码非常相似只是预测部分发生了变化。 谓词不使用 loop2: do {int alt22;//prediction ignores the predicateswitch ( input.LA(1) ) {case LETTER: {alt21;}break;}//matching: either jump out or match another LETTERswitch (alt2) {case 1: {if ( !((somePredicate())) ) {throw new FailedPredicateException(...);}// ... match LETTER ...}break;default:break loop2;} } while (true); 未发现的替代品 保留一些替代方案是完全可以的。 带有谓词的替代方案将按预期工作。 只有在存在多个模棱两可的替代方案时才会始终悬挂门控谓词并且会消除歧义谓词。 门控谓词总是被悬挂 uncoveredGated: LETTER ({347}? LETTER| NUMBER ); 悬挂歧义谓词 uncoveredDisambiguatingHoisted: LETTER ({257}? LETTER*| LETTER ); 非悬挂式歧义谓词 uncoveredDisambiguatingNotHoisted: LETTER ({246}? LETTER| NUMBER ); 门控谓词和歧义消除谓词的组合如果一个备选方案被门控而另一种歧义消除了歧义则始终会提升门控谓词只有在实际需要时才解除歧义消除谓词。 提升了门控谓词而没有消除歧义谓词 combinationDisambiguatingNotHoisted: LETTER ({145}? LETTER| {14!5}? NUMBER ); 两个谓词都被悬挂 combinationDisambiguatingHoisted: LETTER ({156}? LETTER*| {15!6}? LETTER ); 附加括号 如果在括号中关闭歧义谓词则该谓词仍将被视为歧义谓词。 编写歧义谓词的另一种方法 stillDisambiguating: ({224}?) LETTER; testStillDisambiguating: stillDisambiguating | LETTER; 如果在门控谓词周围附加括号则该谓词将被忽略 ignored: ({336}?)LETTER; 回溯 即使解析器正在回溯谓词也会运行例如如果它在语法谓词内部。 如果解析器正在回溯并且谓词失败那么回溯也会失败。 仅当解析器未回溯时才会引发失败的谓词异常。 backtrack规则将启动回溯Backtracking.g LETTER : a..z | A..Z; word: LETTER {123}? LETTER; number: LETTER {23!5}? LETTER;backtrack: (number) number | word; 由于可以进行回溯因此生成的谓词检查是不同的 if ( !((23!5)) ) {if (state.backtracking0) {state.failedtrue; return retval;}throw new FailedPredicateException(input, number, 23!5); } 回溯是条件不得产生副作用必须可重复且评估顺序不重要的另一个原因。 写作条件 本章说明如何为语义谓词编写高级条件。 首先我们将展示如何访问和使用输入令牌流。 我们还将说明如何引用标记的令牌。 最后一部分是关于非悬挂条件下的局部变量。 除非另有说明否则所有使用的示例都位于Environnement.g文件中。 输入令牌流 每个生成的解析器都有公共TokenStream input字段。 该字段提供对整个输入令牌流以及该令牌流中当前位置的访问。 它最重要的方法是Token LT(int k)方法。 参数k包含您感兴趣的令牌的相对位置。 数字1表示“先看一个令牌”数字2表示“先看第二令牌”依此类推。 负数表示传递的令牌-1将返回前一个令牌-2将返回前一个令牌依此类推。 不要使用0。其含义是undefined并且默认解析器返回null 。 注意即使语法处于回溯状态相对引用也可以正常工作。 -1始终是前一个标记1始终是下一个标记。 例子 消除歧义如果 word以字母开头 a 那么它必须至少包含两个字母 word: LETTER ({ input.LT(-1).getText().equals(a)}? LETTER| { !input.LT(-1).getText().equals(a)}? LETTER*); 门控如果所述的第二个数字number是9 那么它必须具有完全相同3标记 number: NUMERAL ({input.LT(1).getText().equals(9)}? NUMERAL NUMERAL| {!input.LT(1).getText().equals(9)}? NUMERAL* ); 注谓语的选择略有事情在这种情况下。 如果输入不符合规则它将影响将引发何种类型的错误。 标签和清单 谓词可以像操作一样引用和使用任何先前定义的标签或标签列表。 标签示例 如果单词的第一个字母是a 那么这个词必须至少有两个字母 labeledWord: aLETTER ({ $a.getText().equals(a)}? LETTER| { !$a.getText().equals(a)}? LETTER*); 标签列表示例如果单词以少于3个字母开头则它必须以数字结尾 labeledListWord: aLETTER ({ $a.size() 3 }? NUMERAL| { $a.size() 3}? ); 注意在这种情况下谓词的选择确实很重要。 上面的示例只有在使用门控{...}?谓词而不是消除{...}?歧义的情况下才能正常工作{...}? 一。 NUMERAL和nothing在语法上是不同的。 消除歧义的谓词将不会用于预测例如不会被提升。 解析器将仅根据下一个标记是NUMERAL吗做出决定。 该条件将用作事后声明以检查字母数是否正确。 这样的语法会在abcd9输入上引发异常而我们的输入会接受它。 未定义标签 谓词不能引用尚未定义的标签。 解析器已生成但首次尝试使用该规则会在运行时引发空指针异常 //this would cause null pointer exception nullPointerAtPredicate: LETTER { $a.getText().equals(a) }? aLETTER; 标签和吊装其他规则 由于必须在使用谓词之前先定义标签并且仅当谓词位于规则的开头时才将其复制到其他规则中因此您不必担心提升到其他规则中。 访问局部变量 Antlr允许您定义自定义局部变量并与一个规则一起使用。 如果您确定谓词不会被复制到其他规则中则可以使用它们。 当然如果可以将谓词复制到其他规则中则使用局部变量将导致错误的解析器。 创建局部变量并在谓词中使用它们。 如果单词以少于10个字母开头则必须以数字结尾 localVariables init {int num0;} //define local variable num: (LETTER { num; })* //raise the num variable by 1 for each letter ( // what should follow depends on the variable value{ num 10 }? NUMERAL| { num 10}? ); 注意适用与之前相同的警告。 我们必须使用门控谓词。 您必须特别小心不要在潜在的提升谓词中使用局部变量。 例如Antlr参考书建议遵循以下规则以仅匹配由少于四个数字组成的数字ANTLRReference3Error.g localVariablesWarning init {int n1;} // n becomes a local variable: ( {n4}? NUMERAL {n;} ) // enter loop only if n4; 上面的规则可以很好地隔离工作即在其他规则中不使用时。 不幸的是如果将其包含在其他规则中则该谓词可能会被提升到该其他规则中ANTLRReference3Error.g // syntax error in generated parser syntaxError: localVariablesWarning | LETTER; n4谓词将被复制到syntaxError规则中。 在该规则内无法访问变量n 并且生成的解析器在语法上将是错误的。 解决初始用例 最后我们将解决激励性章节中描述的两个用例。 关键字–第n个 链接到原始用例。 我们创建了isInsideNth函数该函数仅在先前的令牌与某个第n个伪类的名称匹配时才返回true 。 该函数用作门控谓词内部的条件。 且仅当输入在第n个伪类内时生成的解析器才会假定输入包含第n个表达式。 UseCasesNth.g文件 parser::members {private static SetString NTH_PSEUDOCLASSES new HashSetString();static {NTH_PSEUDOCLASSES.add(nth-child);NTH_PSEUDOCLASSES.add(nth-last-child);NTH_PSEUDOCLASSES.add(nth-of-type);NTH_PSEUDOCLASSES.add(nth-last-of-type);}public boolean isInsideNth() {return isNthPseudoClass(input.LT(-1));}private boolean isNthPseudoClass(Token a) {if (a null)return false;String text a.getText();if (text null)return false;return NTH_PSEUDOCLASSES.contains(text.toLowerCase());}}LPAREN: (; RPAREN: ); COLON: :; COMMA: ,; IDENT : (a..z | A..Z);//pseudoparameters and nth with dummy syntax pseudoparameters: IDENT (COMMA IDENT)*; nth: IDENT; //real nth syntax ommited for simplicity sake// pseudoclass pseudo: COLON COLON? IDENT (({ isInsideNth()}? LPAREN nth RPAREN| LPAREN pseudoparameters RPAREN)?); 具有标签和重写规则的替代解决方案 //different solution - note that we need to use rewrite rules in this case pseudoDifferentSolution: COLON COLON? nameIDENT (({ isNthPseudoClass($name)}? LPAREN nthParametersnth RPAREN| LPAREN parameterspseudoparameters RPAREN)?)- $name $nthParameters? $parameters? ; 重要空白 链接到原始用例。 CSS选择器可以由用组合符 ~和space分隔的多个部分组成。 每个称为简单选择器的部分都以一个可选的元素名称开头然后可以跟随多个伪类属性和类似结构。 忽略空格作为组合器的问题简化的简单选择器语法如下所示 COLON: :; STAR: *; NUMBER: (0..9); IDENT : (a..z | A..Z);//some options have been removed from following rules for simplicity sake elementName: IDENT | STAR | NUMBER; pseudoClass: COLON COLON? IDENT; elementSubsequent: pseudoClass; simpleSelectorWrong: (elementName elementSubsequent*)| elementSubsequent ; 上面的simpleSelectorWrong规则匹配有效的简单选择器 h1 h1:first-child:hover :first-child:hover和:hover 。 不幸的是随着空白的消失上述规则的匹配程度更高。 例如它也将匹配h1:first-child :hover 这应该与h1:first-child *:hover选择器完全一样地解释例如两个简单的选择器由space 。 我们创建了仅在上一个和下一个标记之间没有隐藏标记的情况下才返回true的方法。 除非另有配置否则所有令牌都是CommonToken类的实例。 由于通用令牌知道其起始索引和终止索引因此我们可以对其进行转换和比较以查看它们之间是否存在某些事物。 新的解析器方法UseCasesSelectors.g parser::members {public boolean onEmptyCombinator(TokenStream input) {return !directlyFollows(input.LT(-1), input.LT(1));}private boolean directlyFollows(Token first, Token second) {CommonToken firstT (CommonToken) first;CommonToken secondT (CommonToken) second;if (firstT.getStopIndex() 1 ! secondT.getStartIndex())return false;return true;} } 固定的简单选择器使用gated谓词来检查是否应该继续添加后续元素UseCasesSelectors.g simpleSelector: (elementName ({!onEmptyCombinator(input)}?elementSubsequent)*) | (elementSubsequent ({!onEmptyCombinator(input)}?elementSubsequent)*); 在这种情况下我们必须使用门控谓词。 如果使用歧义谓词则生成的解析器将不会使用谓词来决定是否保留在循环内。 这是因为循环在技术上决定了elementSubsequent和nothing替代方案而这些替代方案在语法上是不同的。 {...}? 谓词不会在预测期间使用只会偶尔抛出异常。 包起来 语义谓词是在语法内部编写的Java条件。 它们将被原样复制到生成的解析器中而没有任何更改。 如果令牌匹配算法到达语义谓词并且该谓词失败则抛出FailedPredicateException异常。 如果规则或替代规则以语义谓词开头则可以在预测阶段使用该语义谓词。 预测阶段中失败的谓词永远不会引发异常但是它们可能会禁用某些替代项。 这称为吊装。 条件必须无副作用可重复且评估顺序无关紧要。 如果将它们提升为其他规则则它们将无法引用局部变量或参数。 语义谓词以三种不同的方式使用作为验证语义谓词作为歧义语义谓词和作为门控语义谓词。 验证语义谓词 验证语义谓词仅充当断言。 结果永远不会悬挂验证语义谓词。 条件在花括号内关闭后跟问号{ condition }? 。 必须将其放置在规则的中间或替代的中间 LETTER : a..z | A..Z; word: LETTER {123}? LETTER; 歧义语义谓词 歧义性语义谓词有助于在语法上等效的替代方案之间进行选择。 结果仅当解析器必须在多个模棱两可的备选方案之间进行选择时才会消除歧义的语义谓词。 歧义语义谓词使用与验证谓词完全相同的语法。 条件在花括号内关闭后跟问号{ condition }? 。 但是必须将它们放在规则的开头或替代的开头 LETTER : a..z | A..Z; // beginning of an alternative alternatives: LETTER ({235}? LETTER*| {235}? LETTER ); 门控语义谓词 门控语义谓语用于动态打开和关闭语法部分。 结果提升了放置在规则或替代规则开头的所有门控谓词。 置于规则或替代规则中间的门控谓词永远不会被悬挂。 条件在花括号内关闭后跟问号和双箭头{ condition }? NUMERAL: 0..9; number: {235}? NUMERAL NUMERAL; 资源资源 Wincent维基 堆栈溢出问题 权威的ANTLR参考 参考 ANTLR –我们的JCG合作伙伴 Maria Jurcovicova的“ 语义谓词”在“ This is Stuff”博客上。 翻译自: https://www.javacodegeeks.com/2012/12/antlr-semantic-predicates.html
http://wiki.neutronadmin.com/news/263307/

相关文章:

  • 珠海网站建设q.479185700強嘉兴做网站的
  • 杭州app开发公司集中郑州seo技术博客
  • 网站代运营服务温岭企业网站建设公司
  • 河南两学一做网站网站制作怎么添加图片
  • 国外网站加速神器默认wordpress菜单去除
  • 太原谁想做网站郑州手机网站制作公司哪家好
  • 学信网网站建设怎么搞wordpress if分类
  • 公司网站制作第一步是什么佛山建设局网站
  • 那些网站平台可以做3d建模建筑网站建设赏析
  • 怎么介绍自己的网站建设知言 wordpress
  • 班级网站建设html制作怎么做模板wordpress
  • 一般公司网站用什么域名套餐平面设计画册设计
  • 中国建设安全协会网站网站建设faq
  • 邵阳汽车网站建设wordpress同类软件
  • 内存数据库 网站开发小程序开发者文档
  • com网站建设如皋建设局网站
  • 文成网站建设什么网址可以免费
  • 龙华住房和建设局网站赣州企业网站建设推广
  • 数据共享网站建设为什么要给企业建设网站?
  • 内蒙古呼和浩特网站建设淘宝网站建设目标
  • 朝阳企业网站建设公司注册地址和经营地址不一样
  • 填写网站信息博野网站建设
  • 凡科能上传自己做的网站河南郑州网站制作
  • 外贸搜索网站电脑网页设计代码模板
  • 东营建设信息网网站手机app定制开发公司
  • c 做网站源码实例wordpress手册下载地址
  • 网站做下载页面微信网页上的网站怎么做
  • 住房和城乡建设部文化中心网站自己制作头像的网站 设计 动漫
  • 建设电影网站怎么上传电影idea怎么做网站
  • 医院建设网站意义宝山网站制作