1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using RegExTokens;
  7 
  8 parser RegExParser
  9 {
 10     uselexer RegExLexer;
 11 
 12     main;
 13 
 14     RegularExpression(soulcm.scmlg.LexerContext* lexerContext) : soulcm.scmlg.Nfa
 15         ::= Alternative(lexerContext):alternative{ return alternative; }
 16         ;
 17 
 18     Alternative(soulcm.scmlg.LexerContext* lexerContext, var soulcm.scmlg.Nfa value) : soulcm.scmlg.Nfa
 19         ::= (Catenation(lexerContext):left{ value = left; } (ALT Catenation(lexerContext):right!{ value = soulcm.scmlg.Alt(*lexerContext, value, right); })*)
 20         {
 21             return value;
 22         }
 23         ;
 24 
 25     Catenation(soulcm.scmlg.LexerContext* lexerContext, var soulcm.scmlg.Nfa value) : soulcm.scmlg.Nfa
 26         ::= (Repetition(lexerContext):left{ value = left; } (Repetition(lexerContext):right{ value = soulcm.scmlg.Cat(value, right); })*)
 27         {
 28             return value;
 29         }
 30         ;
 31 
 32     Repetition(soulcm.scmlg.LexerContext* lexerContext, var soulcm.scmlg.Nfa value) : soulcm.scmlg.Nfa
 33         ::=
 34         (   Primary(lexerContext):left{ value = left; }
 35             (   STAR{ value = soulcm.scmlg.Kleene(*lexerContext, value); }
 36             |   PLUS{ value = soulcm.scmlg.Pos(*lexerContext, value); }
 37             |   QUEST{ value = soulcm.scmlg.Opt(*lexerContext, value); }
 38             )?
 39         )
 40         {
 41             return value;
 42         }
 43         ;
 44 
 45     Primary(soulcm.scmlg.LexerContext* lexerContext, var soulcm.scmlg.Nfa value) : soulcm.scmlg.Nfa
 46         ::=
 47         (   LPAREN Alternative(lexerContext):alt!{ value = alt; } RPAREN!
 48         |   ESCAPE{ value = soulcm.scmlg.MakeNfa(*lexerContext, lexerContext->MakeChar(soulcm.scmlg.MakeEscapeValue(lexer.FileName(), lexer.GetToken(pos)))); }
 49         |   INVERSE{ value = soulcm.scmlg.MakeNfa(*lexerContext, lexerContext->MakeChar('^')); }
 50         |   MINUS{ value = soulcm.scmlg.MakeNfa(*lexerContext, lexerContext->MakeChar('-')); }
 51         |   CHAR{ ustring match = lexer.GetMatch(span); value = soulcm.scmlg.MakeNfa(*lexerContext, lexerContext->MakeChar(match[0])); }
 52         |   DOT{ value = soulcm.scmlg.MakeNfa(*lexerContext, lexerContext->MakeAny()); }
 53         |   Class(lexerContext):cls{ value = soulcm.scmlg.MakeNfa(*lexerContext, cls); }
 54         |   ExpressionReference:ref{ value = lexerContext->MakeExpr(ref); }
 55         )
 56         {
 57             return value;
 58         }
 59         ;
 60 
 61     Class(soulcm.scmlg.LexerContext* lexerContext, var soulcm.scmlg.Class* cls) : soulcm.scmlg.Class*
 62         ::= (LBRACKET{ cls = lexerContext->MakeClass(); } ((INVERSE{ cls->SetInverse(); })? (Range(lexerContext):r{ cls->AddSymbol(r); })*) RBRACKET!)
 63         {
 64             return cls;
 65         }
 66         ;
 67 
 68     Range(soulcm.scmlg.LexerContext* lexerContext, var soulcm.scmlg.Symbol* symbol) : soulcm.scmlg.Symbol*
 69         ::= (Char:s (MINUS Char:e{ symbol = lexerContext->MakeRange(s, e); } | empty{ symbol = lexerContext->MakeChar(s); }))
 70         {
 71             return symbol;
 72         }
 73         ;
 74 
 75     Char : uchar
 76         ::= LPAREN{ return '('; }
 77         |   RPAREN{ return ')'; }
 78         |   LBRACKET{ return '['; }
 79         |   LBRACE{ return '{'; }
 80         |   RBRACE{ return '}'; }
 81         |   ALT{ return '|'; }
 82         |   STAR{ return '*'; }
 83         |   PLUS{ return '+'; }
 84         |   QUEST{ return '?'; }
 85         |   DOT{ return '.'; }
 86         |   ESCAPE{ return soulcm.scmlg.MakeEscapeValue(lexer.FileName(), lexer.GetToken(pos)); }
 87         |   INVERSE{ return '^'; }
 88         |   MINUS{ return '-'; }
 89         |   CHAR{ ustring match = lexer.GetMatch(span); return match[0]; }
 90         ;
 91 
 92     ExpressionReference(var Span s) : ustring
 93         ::= LBRACE{ s = span; } CHAR+ RBRACE{ s.end = span.end; return soulcm.scmlg.MakeExprRefId(lexer.FileName(), lexer.GetMatch(s), lexer.GetToken(pos).line); }
 94         ;
 95 
 96     ruleinfo
 97     {
 98         (RegularExpression, "regular expression"), (Alternative, "alternative"), (Catenation, "catenation"), (Repetition, "repetition"), (Primary, "primary expression"),
 99         (Class, "regular class definition"), (Range, "range"), (Char, "character"), (ExpressionReference, "regular expression reference")
100     }
101 }