| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #include "Common.h" |
| #include "Builtin.h" |
| #include <stdarg.h> |
| #include <stdlib.h> |
| |
| #define ref(name) ExpressionNewIdent(name) |
| #define choice(...) makeExpression(ExpressionNewChoice,__VA_ARGS__,NULL) |
| #define seq(...) makeExpression(ExpressionNewSequence,__VA_ARGS__,NULL) |
| #define and(child) ExpressionNewAnd(child) |
| #define not(child) ExpressionNewNot(child) |
| #define opt(child) ExpressionNewOpt(child) |
| #define star(child) ExpressionNewStar(child) |
| #define plus(child) ExpressionNewPlus(child) |
| #define lit(value) ExpressionNewLit(value) |
| #define cls(...) makeExpression(ExpressionNewClass,__VA_ARGS__,NULL) |
| #define dot() ExpressionNewDot() |
| #define string(child) ExpressionNewString(child) |
| #define range(lo,hi) ExpressionNewRange(lo,hi) |
| |
| static Expression *makeExpression(Expression *(*fun)(int,Expression **), ...) |
| { |
| Expression *children[20]; |
| int count = 0; |
| va_list ap; |
| va_start(ap,fun); |
| Expression *expr; |
| while ((count < 20) && ((expr = va_arg(ap,Expression *)) != NULL)) |
| children[count++] = expr; |
| va_end(ap); |
| return fun(count,children); |
| } |
| |
| Grammar *GrammarNewBuiltin(void) |
| { |
| Grammar *gram = GrammarNew(); |
| |
| // Grammar : Spacing Definition+ EndOfFile |
| GrammarDefine(gram,"Grammar", |
| seq(ref("Spacing"), |
| plus(ref("Definition")), |
| ref("EndOfFile"))); |
| |
| // Definition : Identifier COLON Expression SEMI |
| GrammarDefine(gram,"Definition", |
| seq(ref("Identifier"), |
| ref("COLON"), |
| ref("Expression"), |
| ref("SEMI"))); |
| |
| // Expression : Sequence (BAR Sequence)* |
| GrammarDefine(gram,"Expression", |
| seq(ref("Sequence"), |
| star(seq(ref("BAR"),ref("Sequence"))))); |
| |
| // Sequence : Prefix* |
| GrammarDefine(gram,"Sequence", |
| star(ref("Prefix"))); |
| |
| // Prefix : (AND | NOT)? Suffix |
| GrammarDefine(gram,"Prefix", |
| seq(opt(choice(ref("AND"), |
| ref("NOT"))), |
| ref("Suffix"))); |
| |
| // Suffix : Primary (QUESTION | STAR | PLUS)? |
| GrammarDefine(gram,"Suffix", |
| seq(ref("Primary"), |
| opt(choice(ref("QUESTION"), |
| ref("STAR"), |
| ref("PLUS"))))); |
| |
| // Primary : Identifier !COLON |
| // | DOLLAR OPEN Expression CLOSE |
| // | DOLLAR Identifier OPEN Expression CLOSE |
| // | OPEN Expression CLOSE |
| // | Literal |
| // | Class |
| // | DOT |
| GrammarDefine(gram,"Primary", |
| choice(seq(ref("Identifier"),not(ref("COLON"))), |
| seq(ref("DOLLAR"),ref("OPEN"),ref("Expression"),ref("CLOSE")), |
| seq(ref("DOLLAR"),ref("Identifier"),ref("OPEN"),ref("Expression"),ref("CLOSE")), |
| seq(ref("OPEN"),ref("Expression"),ref("CLOSE")), |
| ref("Literal"), |
| ref("Class"), |
| ref("DOT"))); |
| |
| // Identifier : $(IdentStart IdentCont*) Spacing |
| GrammarDefine(gram,"Identifier", |
| seq(string(seq(ref("IdentStart"), |
| star(ref("IdentCont")))), |
| ref("Spacing"))); |
| |
| // IdentStart : [a-zA-Z_] |
| GrammarDefine(gram,"IdentStart", |
| cls(range('a','z'), |
| range('A','Z'), |
| range('_','_'))); |
| |
| // IdentCont : IdentStart |
| // | [0-9] |
| GrammarDefine(gram,"IdentCont", |
| choice(ref("IdentStart"), |
| cls(range('0','9')))); |
| |
| // Literal : ['] (!['] Char)* ['] Spacing |
| // | ["] (!["] Char)* ["] Spacing |
| GrammarDefine(gram,"Literal", |
| choice(seq(cls(range('\'','\'')), |
| star(seq(not(cls(range('\'','\''))), |
| ref("Char"))), |
| cls(range('\'','\'')), |
| ref("Spacing")), |
| seq(cls(range('"','"')), |
| star(seq(not(cls(range('"','"'))), |
| ref("Char"))), |
| cls(range('"','"')), |
| ref("Spacing")))); |
| |
| // Class : "[" (!"]" Range)* "]" Spacing |
| GrammarDefine(gram,"Class", |
| seq(lit("["), |
| star(seq(not(lit("]")), |
| ref("Range"))), |
| lit("]"), |
| ref("Spacing"))); |
| |
| // Range : Char "-" Char |
| // | Char |
| GrammarDefine(gram,"Range", |
| choice(seq(ref("Char"), |
| lit("-"), |
| ref("Char")), |
| ref("Char"))); |
| |
| // Char : "\\" [nrt'"\[\]\\] |
| // | "\\" [0-2] [0-7] [0-7] |
| // | "\\" [0-7] [0-7]? |
| // | !"\\" . |
| GrammarDefine(gram,"Char", |
| choice(seq(lit("\\"), |
| cls(range('n','n'), |
| range('r','r'), |
| range('t','t'), |
| range('\'','\''), |
| range('"','"'), |
| range('[','['), |
| range(']',']'), |
| range('\\','\\'))), |
| seq(lit("\\"), |
| cls(range('0','2')), |
| cls(range('0','7')), |
| cls(range('0','7'))), |
| seq(lit("\\"), |
| cls(range('0','7')), |
| opt(cls(range('0','7')))), |
| seq(not(lit("\\")),dot()))); |
| |
| // COLON : ":" Spacing |
| GrammarDefine(gram,"COLON",seq(lit(":"),ref("Spacing"))); |
| |
| // SEMI : ";" Spacing |
| GrammarDefine(gram,"SEMI",seq(lit(";"),ref("Spacing"))); |
| |
| // BAR : "|" Spacing |
| GrammarDefine(gram,"BAR",seq(lit("|"),ref("Spacing"))); |
| |
| // AND : "&" Spacing |
| GrammarDefine(gram,"AND",seq(lit("&"),ref("Spacing"))); |
| |
| // NOT : "!" Spacing |
| GrammarDefine(gram,"NOT",seq(lit("!"),ref("Spacing"))); |
| |
| // QUESTION : "?" Spacing |
| GrammarDefine(gram,"QUESTION",seq(lit("?"),ref("Spacing"))); |
| |
| // STAR : "*" Spacing |
| GrammarDefine(gram,"STAR",seq(lit("*"),ref("Spacing"))); |
| |
| // PLUS : "+" Spacing |
| GrammarDefine(gram,"PLUS",seq(lit("+"),ref("Spacing"))); |
| |
| // OPEN : "(" Spacing |
| GrammarDefine(gram,"OPEN",seq(lit("("),ref("Spacing"))); |
| |
| // CLOSE : ")" Spacing |
| GrammarDefine(gram,"CLOSE",seq(lit(")"),ref("Spacing"))); |
| |
| // DOT : "." Spacing |
| GrammarDefine(gram,"DOT",seq(lit("."),ref("Spacing"))); |
| |
| // DOLLAR : "$" Spacing |
| GrammarDefine(gram,"DOLLAR",seq(lit("$"),ref("Spacing"))); |
| |
| // Spacing : $((Space | Comment)*) |
| GrammarDefine(gram,"Spacing",string(star(choice(ref("Space"),ref("Comment"))))); |
| |
| // Comment : "#" (!EndOfLine .)* EndOfLine; |
| GrammarDefine(gram,"Comment", |
| seq(lit("#"), |
| star(seq(not(ref("EndOfLine")), |
| dot())), |
| ref("EndOfLine"))); |
| |
| // Space : " " |
| // | "\t" |
| // | EndOfLine |
| GrammarDefine(gram,"Space", |
| choice(lit(" "), |
| lit("\t"), |
| ref("EndOfLine"))); |
| // EndOfLine : "\r\n" |
| // | "\n" |
| // | "\r" |
| GrammarDefine(gram,"EndOfLine", |
| choice(lit("\r\n"), |
| lit("\n"), |
| lit("\r"))); |
| |
| // EndOfFile : !. |
| GrammarDefine(gram,"EndOfFile",not(dot())); |
| |
| GrammarResolve(gram); |
| |
| return gram; |
| } |