1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23: doctype public "-//IDN etl.sf.net//ETL//Grammar 0.2.1";
24: /// This is a legacy grammar for 0.2.0 syntax defined using 0.2.1 syntax.
25: /// It is used in grammar update script.
26: ///
27: /// This is a definition for the grammar language itself.
28: /// This grammar is actually used for parsing other grammars.
29: /// The text of this specific grammar itself is parsed using bootstrap
30: /// parser, then the grammar is compiled using normal grammar compilation
31: /// path.
32: ///
33: /// The parsing model is AST building. The parser tries to match syntax
34: /// constructs and creates AST according to specified AST constructs.
35: /// AST assumes to contains objects and properties. So AST is directly
36: /// mappable to object models like JavaBeans, EMOF, MOF 1.2, and EMF.
37: ///
38: /// Properties are identified by name and objects are identified by
39: /// namespace URI and name. The object identification idea is borrowed from XMI
40: /// and it is even possible to generate XMI-file without prior knowledge of
41: /// metamodel.
42: ///
43: /// There are two kinds of syntax constructs: expressions and statements.
44: ///
45: /// Expression model is borrowed from prolog. Operator has been borrowed from
46: /// Prolog almost as is. Each operator has priority and associativity.
47: /// Associativity has format "AfA" where A can be "x" or "y", "y" matches
48: /// expression of the same priority and "x" matches expression of lesser
49: /// priority. For example yfx operator is "+" and "-" from C, x+y-z is parsed
50: /// as (x+y)-y. Example of xfy operator is assignment operator from C. a=b=c
51: /// is parsed as a=(b=c).
52: ///
53: /// Note that yfy are not supported yet. You have to choose between yfx or xfy,
54: ///
55: /// Also "f" operators have special semantics, they appear on level 0 and
56: /// are primary operators. They can have neither left nor right part.
57: ///
58: /// Operators can be simple or composite. Simple operators have just a token
59: /// specified. See definition of "|" and "?" operators in this this grammar.
60: /// Composite operators allow more complex syntax constructs. Composite
61: /// operators are used define primary level of the grammar. However they can
62: /// be used to specify non primary operators too. Java method invocation and
63: /// array access operators are examples of this. Composite operator can use
64: /// all syntax expressions used in statements.
65: ///
66: /// Statement defines content of segment returned from term parser. The statement
67: /// is defined using generic constructs like sections, lists, and choice, and
68: /// and tokens.
69: ///
70: /// <author>const</author>
71: grammar net.sf.etl.grammars.Grammar {
72: namespace g = "http://etl.sf.net/etl/grammar/0.2.0";
73:
74: /// This abstract context contains definition used across this grammar.
75: context abstract Base {
76:
77: /// String token definition
78: def String {
79: string(quote="\"") | string(quote='\'');
80: };
81:
82: /// Documentation mapping definition. This mapping is used
83: /// by all statements in the grammar.
84: documentation Documentation {
85: @ documentation += doclines wrapper g:DocumentationLine.text;
86: };
87:
88: /// Definition of object name expression. This reusable fragment
89: /// is used in places where object name is required.
90: def ObjectNameDef {
91: ^ g:ObjectName {
92: @ prefix = identifier;
93: % : {
94: @ name = identifier;
95: };
96: };
97: };
98:
99: /// Definition for wrapper section fragment.
100: def WrapperDef {
101: % wrapper {
102: ref(WrapperObject);
103: };
104: };
105:
106: /// Definition for wrapper specification fragment. Wrapper is
107: /// is usually attached to tokens. When token matches, its value
108: /// wrapped into specified object and property.
109: def WrapperObject {
110: ^ g:Wrapper {
111: @ object = ref(ObjectNameDef);
112: % . {
113: @ property = identifier;
114: };
115: };
116: };
117: };
118:
119:
120:
121: /// This is base mapping syntax context. Mapping context might
122: /// contain blank statements and let statements.
123: context abstract BaseMappingSyntax {
124: include Base;
125:
126: /// Let statement. It is used to define mapping from syntax
127: /// to property of the object. The statement matches expression
128: /// after "=" or "+=". All objects or values that are encountered
129: /// in the property are assigned to property of top object specified
130: /// by name property.
131: ///
132: /// The "+=" version assumes list property, the "=" version assumes
133: /// property with upper multiplicity equal to 1.
134: statement Let {
135: ^ g:Let {
136: % let {
137: @ name = identifier;
138: @ operator = token(+=) | token(=);
139: @ expression = expression;
140: };
141: };
142: };
143:
144: /// This is blank statement. It is used to attach attributes
145: /// and documentation comments. This is may be used for example
146: /// for attaching annotations after last statement.
147: statement BlankStatement {
148: ^ g:BlankSyntaxStatement {
149: };
150: };
151: };
152:
153: /// This is base syntax context. This context might contain object
154: /// specification in addition to let statement.
155: context abstract BaseSyntax {
156: include BaseMappingSyntax;
157:
158: /// Utility definition used in different parts of the syntax
159: def SequenceDef {
160: ^ g:Sequence {
161: @ syntax += block;
162: };
163: };
164:
165: /// Object expression. It is used to specify context of parsing.
166: ///
167: /// The expression matches its content, and creates an context object
168: /// all properties that are directly or indirectly specified in the
169: /// content will be assumed to be specified in context of this object
170: /// unless new object directive is encountered.
171: ///
172: /// It is an error to specify value or object generators inside object
173: /// whithout property layer.
174: op composite Object(f) {
175: ^ g:ObjectOp {
176: % object {
177: @ name = ref(ObjectNameDef);
178: @ syntax = ref(SequenceDef);
179: };
180: };
181: };
182: };
183:
184:
185: /// This is base syntax context.
186: context abstract BaseCompositeSyntax {
187: include BaseSyntax;
188:
189: /// Expression statement. This statement is a container for expression.
190: /// The statement has the same semantics as expression contained in it.
191: statement Expression {
192: ^ g:ExpressionStatement {
193: @ syntax = expression;
194: };
195: };
196:
197:
198: };
199:
200:
201: /// This syntax is used inside documentation statement.
202: context DocumentationSyntax {
203: include BaseMappingSyntax;
204: /// This is doclines expression. It matches sequence of documentation lines.
205: /// <example>
206: /// let documentation += doclines wrapper xj:DocumentationLine.text;
207: /// </example>
208: op composite Doclines(f) {
209: ^ g:DocLinesOp {
210: % doclines {
211: @ wrapper = ref(WrapperDef)?;
212: };
213: };
214: };
215: };
216:
217: /// This context specifies syntax for simple operations
218: context SimpleOpSyntax {
219: include BaseCompositeSyntax;
220:
221: /// This expression matches left operand in expression. It is used
222: /// in let expression to specify property to which left operand
223: /// of operator should be assigned.
224: op composite Left(f) {
225: ^ g:OperandOp {
226: @ position = token(left);
227: };
228: };
229:
230: /// This expression matches right operand in expression. It is used
231: /// in let expression to specify property to which right operand
232: /// of operator should be assigned.
233: op composite Right(f) {
234: ^ g:OperandOp {
235: @ position = token(right);
236: };
237: };
238: };
239:
240: /// This context contains definition of primitive syntax operators
241: context abstract CompositeOperatorsSyntax {
242: include BaseCompositeSyntax;
243:
244:
245: /// Choice operator. It matches one of two alternatives.
246: op ChoiceOp(xfy,300,|) {
247: ^ g:ChoiceOp { @ options += left; @ options += right; };
248: };
249:
250: /// First choice operator. It tries to match the first
251: /// alternative than the second one.
252: op FirstChoiceOp(xfy,200,/) {
253: ^ g:FirstChoiceOp { @ first = left; @ second = right; };
254: };
255:
256:
257: /// This operator matches empty sequence of tokens or its operand.
258: op OptionalOp(yf,100,?) {
259: ^ g:OptionalOp { @ syntax = left; };
260: };
261:
262: /// This operator matches non empty sequence of specified operand.
263: op OneOrMoreOp(yf,100,+) {
264: ^ g:OneOrMoreOp { @ syntax = left; };
265: };
266:
267: /// This operation is composition of optional and one of more operators.
268: /// Basically it is the composition of + and ? operators.
269: op ZeroOrMoreOp(yf,100,*) {
270: ^ g:ZeroOrMoreOp { @ syntax = left; };
271: };
272:
273: };
274:
275: /// This context defines expressions that might happen in context
276: /// of modifiers expressions.
277: context ModifiersSyntax {
278: include BaseMappingSyntax;
279:
280: /// This is modifier specification. It can contain optional wrapper.
281: op composite ModifierOp(f) {
282: ^ g:ModifierOp {
283: % modifier {
284: @ value = token;
285: @ wrapper = ref(WrapperDef)?;
286: };
287: };
288: };
289: };
290:
291:
292: context CompositeSyntax {
293: include CompositeOperatorsSyntax;
294: import ModifiersSyntax = ModifiersSyntax;
295:
296:
297: /// Sequence statement is a simple block. Elements in this blocks are
298: /// matched sequentially. It is used to group syntax elements together.
299: op composite Sequence(f) {
300: ref(SequenceDef);
301: };
302:
303: /// This is a section. The section matches token specified as its name
304: /// and then an expression specified as its body. The section prefix is
305: /// intended to be unique in the context where section occurs. The section
306: /// token is not reported as value to parser.
307: op composite SectionOp(f) {
308: ^ g:SectionOp {
309: % section {
310: @ name = token;
311: @ syntax = ref(SequenceDef);
312: };
313: };
314: };
315:
316: /// Reference to definition in this context or in included context.
317: /// The expression is replaced with content of original definition.
318: /// Recursion is not allowed to be created using references.
319: op composite RefOp(f) {
320: ^ g:RefOp {
321: % ref % ( {
322: @ name = identifier;
323: } % ) ;
324: };
325: };
326:
327: /// Block reference. The statement matches block that that contains
328: /// statements of the specified context. If no context is specified,
329: /// reference to current context is assumed. Block produces a possibly
330: /// empty sequence of objects. And it should happen in context of
331: /// of list property.
332: op composite BlockRef(f) {
333: ^ g:BlockRef {
334: % block {
335: % ( {
336: @ context = identifier;
337: } % ) ?;
338: };
339: };
340: };
341:
342: /// This is reusable fragment used to specify expression priority
343: def ExpressionPriorityDef {
344: % priority % = {
345: @ priority = integer;
346: };
347: };
348: /// Expression reference. This reference matches expression from
349: /// specified context and of specified priority. If context is omitted,
350: /// current context is assumed. The expression production always
351: /// produces a single object as result if parsing is successful.
352: op composite ExpressionRef(f) {
353: ^ g:ExpressionRef {
354: % expression {
355: % ( {
356: {
357: ref(ExpressionPriorityDef);
358: } | {
359: @ context = identifier;
360: % , {
361: ref(ExpressionPriorityDef);
362: }?;
363: };
364: } % ) ?;
365: };
366: };
367: };
368:
369:
370: /// This construct matches sequence separated by the specified
371: /// separator. This construct is just a useful shorthand. The separator
372: /// can be any specific token. The expression
373: ///
374: /// list , {
375: /// <content>;
376: /// }
377: ///
378: /// is equivalent to
379: ///
380: /// {
381: /// <content>;
382: /// section , {
383: /// <content>;
384: /// }*;
385: /// }
386: op composite List(f) {
387: ^ g:ListOp {
388: % list {
389: @ separator = token;
390: @ syntax = ref(SequenceDef);
391: };
392: };
393: };
394:
395: /// this construct matches brackets and syntax enclosed in brackets.
396: /// This construct is just a useful shorthand. The separator
397: /// can be any specific token. For example, the expression
398: /// brackets ( ) {
399: /// <content>;
400: /// }
401: ///
402: /// is equivalent to
403: ///
404: /// section ( {
405: /// <content>;
406: /// section ) {};
407: /// };
408: op composite BracketsOp(f) {
409: ^ g:BracketsOp {
410: % brackets {
411: @ open = token;
412: @ close = token;
413: @ syntax = ref(SequenceDef);
414: };
415: };
416: };
417:
418: /// This construct matches set of modifiers. This construct
419: /// matches any number or modifiers in any order. Each modifier
420: /// if matches produces its text as a value. Wrapper specified
421: /// for modifiers construct applies to all modifiers inside it
422: /// unless overridden by modifier.
423: op composite ModifiersOp(f) {
424: ^ g:ModifiersOp {
425: % modifiers {
426: @ wrapper = ref(WrapperDef)?;
427: @ modifiers += block(ModifiersSyntax);
428: };
429: };
430: };
431:
432: /// This construct matches any token or token specified in brackets.
433: /// It produces a value of its text. If no token is specified,
434: /// the construct matches any significant token with exception of
435: /// documentation comment. See this grammar for numerous examples of its
436: /// usage (including this definition).
437: ///
438: /// Optional wrapper causes wrapping value produced by this expression
439: /// into specified wrapper.
440: op composite TokenOp(f) {
441: ^ g:TokenOp {
442: % token {
443: % ( {
444: @ value = token;
445: } % ) ?;
446: };
447: @ wrapper = ref(WrapperDef)?;
448: };
449: };
450:
451: /// This operator matches string with specified quote kind.
452: /// The quote must be specified. The operator produces matched text
453: /// as a value.
454: ///
455: /// Optional wrapper causes wrapping value produced by this expression
456: /// into specified wrapper.
457: op composite StringOp(f) {
458: ^ g:StringOp {
459: % string % ( % quote % = {
460: @ quote = ref(String);
461: } % );
462: @ wrapper = ref(WrapperDef)?;
463: };
464: };
465:
466: /// This operator matches any identifier. The operator produces matched text
467: /// as a value.
468: ///
469: /// Optional wrapper causes wrapping value produced by this expression
470: /// into specified wrapper.
471: op composite IdentifierOp(f) {
472: ^ g:IdentifierOp {
473: % identifier {
474: };
475: @ wrapper = ref(WrapperDef)?;
476: };
477: };
478:
479:
480: /// This operator matches integer without suffix or with specified suffix
481: /// The operator produces matched text as a value.
482: ///
483: /// Optional wrapper causes wrapping value produced by this expression
484: /// into specified wrapper.
485: op composite IntegerOp(f) {
486: ^ g:IntegerOp {
487: % integer {
488: % ( {
489: % suffix % = {
490: @ suffix = ref(String);
491: }?;
492: } % ) ?;
493: @ wrapper = ref(WrapperDef)?;
494: };
495: };
496: };
497:
498:
499: /// This operator matches float without suffix or with specified suffix.
500: /// The operator produces matched text as a value.
501: ///
502: /// Optional wrapper causes wrapping value produced by this expression
503: /// into specified wrapper.
504: op composite FloatOp(f) {
505: ^ g:FloatOp {
506: % float {
507: % ( {
508: % suffix % = {
509: @ suffix = ref(String);
510: }? ;
511: } % ) ?;
512: };
513: @ wrapper = ref(WrapperDef)?;
514: };
515: };
516:
517:
518: /// This operator matches any graphics token.
519: /// The operator produces matched text as a value.
520: ///
521: /// Optional wrapper causes wrapping value produced by this expression
522: /// into specified wrapper.
523: op composite GraphicsOp(f) {
524: ^ g:GraphicsOp {
525: % graphics;
526: @ wrapper = ref(WrapperDef)?;
527: };
528: };
529:
530: };
531:
532: /// Composite operator syntax.
533: /// Note that this definition is oversimplified. There are additional
534: /// constraint that "left" and "right" expression might happen only on top
535: /// level. The construct will be possibly adjusted later.
536: context CompositeOpSyntax {
537: include SimpleOpSyntax;
538: include CompositeSyntax;
539: };
540:
541: /// This context defines content of context statement. So it defines itself.
542: context ContextContent {
543: include Base;
544: import compositeOpSyntax = CompositeOpSyntax;
545: import simpleOpSyntax = SimpleOpSyntax;
546: import compositeSyntax = CompositeSyntax;
547: import documentationSyntax = DocumentationSyntax;
548:
549: /// This is blank statement. It is used to attach attributes
550: /// and documentation comments.
551: statement BlankStatement {
552: ^ g:BlankContextMember {
553: };
554: };
555:
556: /// Operator associativity definition. It matches any valid associativity.
557: def OpAssociativity {
558: token(f) | token(xf) | token(yf) |token(xfy) |
559: token(xfx) |token(yfx) |token(fx) |token(fy);
560: };
561:
562: /// Simple operator. See grammar comment for details.
563: statement SimpleOp {
564: ^ g:SimpleOp {
565: % simple {
566: @ name = identifier;
567: % ( {
568: @ associativity = ref(OpAssociativity);
569: % , {
570: @ priority = integer;
571: } % , {
572: @ text = token;
573: };
574: } % );
575: @ syntax += block(simpleOpSyntax);
576: };
577: };
578: };
579:
580: /// Composite operator. See grammar comment for details.
581: statement CompositeOp {
582: ^ g:CompositeOp {
583: % composite {
584: @ name = identifier;
585: % ( {
586: @ associativity = ref(OpAssociativity);
587: % , {
588: @ priority = integer;
589: }?;
590: } % );
591: @ syntax += block(compositeOpSyntax);
592: };
593: };
594: };
595:
596:
597: /// Attributes definition. Attributes can be applied only to
598: /// statements. To apply them to expressions, define an composite
599: /// operator that uses the same syntax. Such operator and attributes
600: /// declaration can share syntax through def statement.
601: statement Attributes {
602: ^ g:Attributes {
603: % attributes {
604: @ name = identifier;
605: @ syntax += block(compositeSyntax);
606: };
607: };
608: };
609:
610: /// Statement definition. Statement attempt to match entire segment.
611: /// If statement matches part of segment and there are some
612: /// unmatched significant tokens left, it is a syntax error.
613: statement Statement {
614: ^ g:Statement {
615: % statement {
616: @ name = identifier;
617: @ syntax += block(compositeSyntax);
618: };
619: };
620: };
621:
622: /// Documentation syntax. It matches documentation comments before
623: /// start of grammar. The definition is used to specify property
624: /// where documentation is put.
625: statement DocumentationSyntax {
626: ^ g:DocumentationSyntax {
627: % documentation {
628: @ name = identifier;
629: @ syntax += block(documentationSyntax);
630: };
631: };
632: };
633:
634: /// A fragment definition. It is used to define reusable parts of the
635: /// syntax. References to definitions are replaced with content of the
636: /// definition, so it is an error for definition to refer to itself
637: /// through ref construct.
638: statement Def {
639: ^ g:Def {
640: % def {
641: @ name = identifier;
642: @ syntax += block(compositeSyntax);
643: };
644: };
645: };
646:
647: /// Include operation cause all definitions except redefined
648: /// to be included in this context. It is an error if two definitions
649: /// are available using different paths. If wrapper chain is specified
650: /// The statements will be wrapped into the specified chain.
651: statement ContextInclude {
652: ^ g:ContextInclude {
653: % include {
654: @ contextName = identifier;
655: @ wrappers += % wrapper {
656: list / {
657: ref(WrapperObject);
658: };
659: }?;
660: };
661: };
662: };
663:
664: /// Import operation makes context referenceable from this context or
665: /// allows redefinition of context reference.
666: statement ContextImport {
667: ^ g:ContextImport {
668: % import {
669: @ localName = identifier;
670: % = {
671: @ contextName = identifier;
672: % from {
673: @ grammarName = identifier;
674: }?;
675: };
676: };
677: };
678: };
679: };
680:
681: /// This context defines grammar content.
682: context GrammarContent {
683: include Base;
684: import contextContent = ContextContent;
685:
686: /// This definition provides way of referencing other grammars.
687: def GrammarRef {
688: {
689: @ systemId = ref(String);
690: % public {
691: @ publicId = ref(String);
692: }?;
693: } | {
694: % public {
695: @ publicId = ref(String);
696: };
697: };
698: };
699:
700: /// This is blank statement. It is used to attach attributes
701: /// and documentation comments.
702: statement BlankStatement {
703: ^ g:BlankGrammarMember {
704: };
705: };
706:
707:
708: /// This is an include statement. Include causes all context from
709: /// included grammar to be added to current grammar. The definitions
710: /// from grammar include are added only if current grammar does not
711: /// have definitions with the same name.
712: ///
713: /// Grammar imports and context imports also follow this inclusion rule.
714: /// It is an error to include two different non-shadowed definitions by
715: /// different include paths.
716: statement Include {
717: ^ g:GrammarInclude {
718: % include {
719: ref(GrammarRef);
720: };
721: };
722: };
723:
724: /// This is grammar import statement. A statement allows contexts of this
725: /// grammar to import context from specified grammar.
726: statement Import {
727: ^ g:GrammarImport {
728: % import {
729: @ name = identifier;
730: } % = {
731: ref(GrammarRef);
732: };
733: };
734: };
735:
736:
737: /// Namespace declaration is used to declare namespace prefix. The
738: /// prefix declaration is local to grammar.
739: statement Namespace {
740: ^ g:Namespace {
741: % namespace {
742: @ prefix = identifier;
743: % = {
744: @ uri = ref(String);
745: };
746: };
747: };
748: };
749:
750: /// Context definition. This definition is used to define context.
751: /// Context may be default and abstract. Abstract contexts
752: /// cannot be used for parsing and are used only in context include.
753: /// Abstract contexts may be imported only by abstract contexts.
754: ///
755: /// Default context is a context that used to parse source when
756: /// no context is specified in doctype.
757: statement Context {
758: ^ g:Context {
759: % context {
760: modifiers wrapper g:Modifier.value {
761: @ abstractModifier = modifier abstract;
762: @ defaultModifier = modifier default;
763: };
764: @ name = identifier;
765: @ content += block(contextContent);
766: };
767: };
768: };
769: };
770:
771: /// This context contains definition of grammar construct itself
772: context default GrammarSource {
773: include Base;
774: import grammarContent = GrammarContent;
775:
776: /// This is blank statement. It is used to attach attributes
777: /// and documentation comments. It is ignored during grammar
778: /// compilation.
779: statement BlankStatement {
780: ^ g:BlankTopLevel {
781: };
782: };
783:
784: /// Grammar statement. It defines grammar. Grammar name is purely
785: /// informative and is used in reported events to identify grammar
786: /// by logical name rather by URI that happens to be current grammar
787: /// location.
788: ///
789: /// Grammar can be abstract, in that case it cannot be instantiated
790: /// and referenced from doctype. It can be only included into other
791: /// grammars.
792: statement Grammar {
793: ^ g:Grammar {
794: % grammar {
795: modifiers wrapper g:Modifier.value {
796: @ abstractModifier = modifier abstract;
797: };
798: @ name += list . {identifier;};
799: @ content += block(grammarContent);
800: };
801: };
802: };
803: };
804: };