1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System.Lex;
  7 using Cm.Ast;
  8 using ParserFileTokens;
  9 
 10 parser ParserFileParser
 11 {
 12     uselexer ParserFileLexer;
 13     main;
 14 
 15     using IdentifierParser.QualifiedId;
 16     using IdentifierParser.Identifier;
 17     using TypeExprParser.TypeExpr;
 18     using ExpressionParser.ExpressionList;
 19     using StatementParser.CompoundStatement;
 20 
 21     ParserFile(ParsingContext* parsingContext, var UniquePtr<soulcm.scmpg.ParserFile> parserFile) : soulcm.scmpg.ParserFile*
 22         ::= (empty{ parserFile.Reset(new soulcm.scmpg.ParserFile(lexer.FileName())); } Declaration(parserFile.Get(), parsingContext):declaration*)
 23         {
 24             return parserFile.Release();
 25         }
 26         ;
 27 
 28     Declaration(soulcm.scmpg.ParserFile* parserFile, ParsingContext* parsingContext)
 29         ::= UsingDirective(parsingContext):usingDirective{ parserFile->AddUsingDirective(usingDirective); }
 30         |   ParserDeclaration(parsingContext):parserDeclaration{ parserFile->AddParser(parserDeclaration); }
 31         ;
 32 
 33     UsingDirective(ParsingContext* ctx) : Node*
 34         ::= UsingAliasDirective(ctx):usingAlias{ return usingAlias; }
 35         |   UsingNamespaceDirective(ctx):usingNs{ return usingNs; }
 36         ;
 37 
 38     UsingAliasDirective(ParsingContext* ctx, var Span s) : Node*
 39         ::= USING{ s = span; } Identifier(ctx):id ASSIGN QualifiedId(ctx):qid! SEMICOLON!
 40         {
 41             s.end = span.end;
 42             return new AliasNode(s, ctx->ModuleId(), id, qid);
 43         }
 44         ;
 45 
 46     UsingNamespaceDirective(ParsingContext* ctx, var Span s) : Node*
 47         ::= USING{ s = span; } QualifiedId(ctx):ns! SEMICOLON!
 48         {
 49             s.end = span.end;
 50             return new NamespaceImportNode(s, ctx->ModuleId(), ns);
 51         }
 52         ;
 53 
 54     ParserDeclaration(ParsingContext* parsingContext, var UniquePtr<soulcm.scmpg.GrammarParser> grammarParser) : soulcm.scmpg.GrammarParser*
 55         ::= (PARSER ID{ grammarParser.Reset(new soulcm.scmpg.GrammarParser(lexer.GetMatch(span), u"")); } LBRACE! Statement(grammarParser.Get(), parsingContext):statement* RBRACE!)
 56         {
 57             return grammarParser.Release();
 58         }
 59         ;
 60 
 61     Statement(soulcm.scmpg.GrammarParser* grammarParser, ParsingContext* parsingContext)
 62         ::= MainStatement(grammarParser):mainStatement
 63         |   StartStatement(grammarParser):startStatement
 64         |   NothrowStatement(grammarParser):nothrowStatement
 65         |   FarthestErrorStatement(grammarParser):farthestErrorStatement
 66         |   StateStatement(grammarParser):stateStatement
 67         |   UsingStatement(grammarParser):usingStatement
 68         |   LexerStatement(grammarParser):lexerStatement
 69         |   RuleInfoStatement(grammarParser):ruleInfoStatement
 70         |   RuleStatement(grammarParser, parsingContext):ruleStatement
 71         ;
 72 
 73     MainStatement(soulcm.scmpg.GrammarParser* grammarParser)
 74         ::= MAIN SEMICOLON!{ grammarParser->SetMain(); }
 75         ;
 76 
 77     StartStatement(soulcm.scmpg.GrammarParser* grammarParser)
 78         ::= START SEMICOLON!{ grammarParser->SetStart(); }
 79         ;
 80 
 81     NothrowStatement(soulcm.scmpg.GrammarParser* grammarParser)
 82         ::= NOTHROW SEMICOLON!{ grammarParser->SetNothrow(); }
 83         ;
 84 
 85     FarthestErrorStatement(soulcm.scmpg.GrammarParser* grammarParser)
 86         ::= FARTHEST_ERROR SEMICOLON!{ grammarParser->SetFarthestError(); }
 87         ;
 88 
 89     StateStatement(soulcm.scmpg.GrammarParser* grammarParser)
 90         ::= STATE SEMICOLON!{ grammarParser->SetState(); }
 91         ;
 92     
 93     UsingStatement(soulcm.scmpg.GrammarParser* grammarParser)
 94         ::= USING UsingQualifiedId:parserId! SEMICOLON!{ grammarParser->AddUsing(parserId); }
 95         ;
 96 
 97     UsingQualifiedId(var Span s) : ustring
 98         ::= (ID{ s = span; } (DOT ID{ s.end = span.end; })*){ return lexer.GetMatch(s); }
 99         ;
100 
101     LexerStatement(soulcm.scmpg.GrammarParser* grammarParser, var ustring lexerName)
102         ::= USELEXER ID!{ lexerName = lexer.GetMatch(span); } SEMICOLON!{ grammarParser->SetLexer(lexerName); }
103         ;
104 
105     RuleInfoStatement(soulcm.scmpg.GrammarParser* grammarParser)
106         ::= RULEINFO LBRACE! (RuleInfo(grammarParser):ruleInfo % COMMA)? RBRACE!
107         ;
108 
109     RuleInfo(soulcm.scmpg.GrammarParser* grammarParser, var ustring ruleName, var ustring ruleInfo)
110         ::= LPAREN ID!{ ruleName = lexer.GetMatch(span); } COMMA! STRINGLIT!{ ruleInfo = soulcm.scmpg.ParseStringLiteral(lexer.FileName(), lexer.GetToken(pos)); } RPAREN!
111         {
112             grammarParser->AddRuleInfo(ruleName, ruleInfo);
113         }
114         ;
115 
116     RuleStatement(soulcm.scmpg.GrammarParser* grammarParser, ParsingContext* parsingContext, var UniquePtr<soulcm.scmpg.RuleParser> rule)
117         ::= ID{ ustring id = lexer.GetMatch(span); rule.Reset(new soulcm.scmpg.RuleParser(id)); } ParametersAndVariables(rule.Get(), parsingContext):paramsAndVars?
118             ReturnType(parsingContext):returnType? PRODUCES RuleBody(parsingContext):definition! SEMICOLON!
119         {
120             rule->SetDefinition(definition);
121             rule->SetReturnType(returnType);
122             grammarParser->AddRule(rule.Release());
123         }
124         ;
125 
126     ParametersAndVariables(soulcm.scmpg.RuleParser* rule, ParsingContext* parsingContext)
127         ::= LPAREN (ParamOrVariable(parsingContext):paramOrVariable{ rule->AddParamOrVariable(paramOrVariable); } % COMMA)? RPAREN!
128         ;
129 
130     ParamOrVariable(ParsingContext* parsingContext) : soulcm.scmpg.Parameter*
131         ::= VAR TypeExpr(parsingContext):varType Identifier(parsingContext):varName{ return new soulcm.scmpg.Variable(varType, varName); }
132         |   TypeExpr(parsingContext):paramType Identifier(parsingContext):paramName{ return new soulcm.scmpg.Parameter(paramType, paramName); }
133         ;
134 
135     ReturnType(ParsingContext* parsingContext) : Node*
136         ::= COLON TypeExpr(parsingContext):type{ return type; }
137         ;
138 
139     RuleBody(ParsingContext* parsingContext) : soulcm.scmpg.Parser*
140         ::= Alternative(parsingContext):alt{ return alt; }
141         ;
142 
143     Alternative(ParsingContext* parsingContext, var UniquePtr<soulcm.scmpg.Parser> value) : soulcm.scmpg.Parser*
144         ::= (Sequence(parsingContext):left{ value.Reset(left); } (BITOR Sequence(parsingContext):right!{ value.Reset(new soulcm.scmpg.AlternativeParser(value.Release(), right)); })*)
145         {
146             return value.Release();
147         }
148         ;
149 
150     Sequence(ParsingContext* parsingContext, var UniquePtr<soulcm.scmpg.Parser> value) : soulcm.scmpg.Parser*
151         ::= (Difference(parsingContext):left{ value.Reset(left); } (Difference(parsingContext):right{ value.Reset(new soulcm.scmpg.SequenceParser(value.Release(), right)); })*)
152         {
153             return value.Release();
154         }
155         ;
156 
157     Difference(ParsingContext* parsingContext, var UniquePtr<soulcm.scmpg.Parser> value) : soulcm.scmpg.Parser*
158         ::= (List(parsingContext):left{ value.Reset(left); } (MINUS List(parsingContext):right!{ value.Reset(new soulcm.scmpg.DifferenceParser(value.Release(), right)); })*)
159         {
160             return value.Release();
161         }
162         ;
163 
164     List(ParsingContext* parsingContext, var UniquePtr<soulcm.scmpg.Parser> value) : soulcm.scmpg.Parser*
165         ::= (Postfix(parsingContext):left{ value.Reset(left); } (REM Postfix(parsingContext):right!{ value.Reset(new soulcm.scmpg.ListParser(value.Release(), right)); })?)
166         {
167             return value.Release();
168         }
169         ;
170 
171     Postfix(ParsingContext* parsingContext, var UniquePtr<soulcm.scmpg.Parser> value) : soulcm.scmpg.Parser*
172         ::=
173         (   Primary(parsingContext):primary{ value.Reset(primary); }
174             (   STAR{ value.Reset(new soulcm.scmpg.KleeneParser(value.Release())); }
175             |   PLUS{ value.Reset(new soulcm.scmpg.PositiveParser(value.Release())); }
176             |   QUEST{ value.Reset(new soulcm.scmpg.OptionalParser(value.Release())); }
177             )?
178         )
179         {
180             return value.Release();
181         }
182         ;
183 
184     Primary(ParsingContext* parsingContext, var UniquePtr<soulcm.scmpg.Parser> value) : soulcm.scmpg.Parser*
185         ::=
186         (
187             (   RuleCall(parsingContext):ruleCall{ value.Reset(ruleCall); }
188             |   Primitive:primitive{ value.Reset(primitive); }
189             |   Grouping(parsingContext):grouping{ value.Reset(grouping); }
190             )
191             (
192                 EXCLAMATION{ value.Reset(new soulcm.scmpg.ExpectationParser(value.Release())); }
193             )?
194             (
195                 (
196                     (CompoundStatement(parsingContext):successCode
197                     (DIV CompoundStatement(parsingContext):failureCode)?){ value.Reset(new soulcm.scmpg.ActionParser(successCode, failureCode, value.Release())); }
198                 )
199             )?
200         )
201         {
202             return value.Release();
203         }
204         ;
205 
206     RuleCall(ParsingContext* parsingContext, var ustring ruleName, var UniquePtr<InvokeNode> invoke, var long nonterminalPos) : soulcm.scmpg.Parser*
207         ::= Nonterminal:nt{ ruleName = nt; nonterminalPos = pos; invoke.Reset(new InvokeNode(Span(), parsingContext->ModuleId())); }
208             (LPAREN{ pass = NoWhiteSpaceBetweenTokens(lexer.GetToken(nonterminalPos), lexer.GetToken(pos)); }
209             ExpressionList(parsingContext, invoke.Get()):args RPAREN)? COLON ID!
210         {
211             ustring name = lexer.GetMatch(span);
212             soulcm.scmpg.NonterminalParser* nonterminalParser = new soulcm.scmpg.NonterminalParser(name, ruleName);
213             nonterminalParser->SetArguments(invoke.Get());
214             return nonterminalParser;
215         }
216         ;
217 
218     Nonterminal : ustring
219         ::= ID{ return lexer.GetMatch(span); }
220         ;
221 
222     Primitive : soulcm.scmpg.Parser*
223         ::= EMPTY
224         {
225             return new soulcm.scmpg.EmptyParser();
226         }
227         |   ANY
228         {
229             return new soulcm.scmpg.AnyParser();
230         }
231         |   ID
232         {
233             ustring tokenName = lexer.GetMatch(span);
234             return new soulcm.scmpg.TokenParser(tokenName);
235         }
236         |   CHARLIT
237         {
238             uchar charLit = soulcm.scmpg.ParseCharLiteral(lexer.FileName(), lexer.GetToken(pos));
239             return new soulcm.scmpg.CharParser(charLit);
240         }
241         |   STRINGLIT
242         {
243             ustring strLit = soulcm.scmpg.ParseStringLiteral(lexer.FileName(), lexer.GetToken(pos));
244             if (strLit.Length() > 0 && strLit[0] == '[' && strLit[strLit.Length() - 1] == ']')
245             {
246                 soulcm.scmpg.CharSet charSet = soulcm.scmpg.ParseCharSet(lexer.FileName(), lexer.GetToken(pos), strLit);
247                 return new soulcm.scmpg.CharSetParser(charSet);
248             }
249             else
250             {
251                 return new soulcm.scmpg.StringParser(strLit);
252             }
253         }
254         ;
255 
256     Grouping(ParsingContext* parsingContext) : soulcm.scmpg.Parser*
257         ::= (LPAREN Alternative(parsingContext):alt RPAREN!){ return new soulcm.scmpg.GroupingParser(alt); }
258         ;
259 }