1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using Cm.Ast;
  7 using LexerFileTokens;
  8 
  9 parser LexerFileParser
 10 {
 11     uselexer LexerFileLexer;
 12 
 13     using IdentifierParser.Identifier;
 14     using IdentifierParser.QualifiedId;
 15     using TypeExprParser.TypeExpr;
 16     using StatementParser.CompoundStatement;
 17 
 18     main;
 19 
 20     LexerFile(var UniquePtr<soulcm.scmlg.LexerFile> lexerFile, ParsingContext* parsingContext) : soulcm.scmlg.LexerFile*
 21         ::= empty{ lexerFile.Reset(new soulcm.scmlg.LexerFile()); }
 22         (
 23             (Declaration(parsingContext):declaration{ lexerFile->Add(declaration); })*
 24         )
 25         {
 26             return lexerFile.Release();
 27         }
 28         ;
 29 
 30     Declaration(ParsingContext* parsingContext) : soulcm.scmlg.Declaration*
 31         ::= ClassMap:classMapDeclaration{ return classMapDeclaration; }
 32         |   Usings(parsingContext):usingDeclarations{ return usingDeclarations; }
 33         |   Tokens:tokensDeclaration{ return tokensDeclaration; }
 34         |   Keywords:keywordsDeclaration{ return keywordsDeclaration; }
 35         |   Expressions:expressionsDeclaration{ return expressionsDeclaration; }
 36         |   Lexer(parsingContext):lexerDeclaration{ return lexerDeclaration; }
 37         ;
 38 
 39     ClassMap(var ustring classMapName) : soulcm.scmlg.ClassMap*
 40         ::= CLASSMAP ID!{ classMapName = lexer.GetMatch(span); } SEMICOLON!{ return new soulcm.scmlg.ClassMap(classMapName); }
 41         ;
 42 
 43     Usings(ParsingContext* ctx, var UniquePtr<soulcm.scmlg.Usings> usings) : soulcm.scmlg.Usings*
 44         ::= empty{ usings.Reset(new soulcm.scmlg.Usings()); } UsingDirectives(ctx, usings.Get()):usingDirectives{ return usings.Release(); }
 45         ;
 46 
 47     UsingDirectives(ParsingContext* ctx, soulcm.scmlg.Usings* usings)
 48         ::= UsingDirective(ctx, usings):usingDirective+
 49         ;
 50 
 51     UsingDirective(ParsingContext* ctx, soulcm.scmlg.Usings* usings)
 52         ::= UsingAliasDirective(ctx):usingAlias{ usings->AddMember(usingAlias); }
 53         |   UsingNamespaceDirective(ctx):usingNs{ usings->AddMember(usingNs); }
 54         ;
 55 
 56     UsingAliasDirective(ParsingContext* ctx, var Span s) : Node*
 57         ::= USING{ s = span; } Identifier(ctx):id ASSIGN QualifiedId(ctx):qid! SEMICOLON!
 58         {
 59             s.end = span.end;
 60             return new AliasNode(s, ctx->ModuleId(), id, qid);
 61         }
 62         ;
 63 
 64     UsingNamespaceDirective(ParsingContext* ctx, var Span s) : Node*
 65         ::= USING{ s = span; } QualifiedId(ctx):ns! SEMICOLON!
 66         {
 67             s.end = span.end;
 68             return new NamespaceImportNode(s, ctx->ModuleId(), ns);
 69         }
 70         ;
 71 
 72     Tokens(var ustring tokensDeclarationName, var UniquePtr<soulcm.scmlg.Tokens> tokens) : soulcm.scmlg.Tokens*
 73         ::= TOKENS ID!{ tokensDeclarationName = lexer.GetMatch(span); } LBRACE!{ tokens.Reset(new soulcm.scmlg.Tokens(tokensDeclarationName)); }
 74             (Token:token{ tokens->Add(token); } % COMMA)? RBRACE!
 75         {
 76             return tokens.Release();
 77         }
 78         ;
 79 
 80     Token(var ustring tokenName, var ustring tokenInfo) : soulcm.scmlg.Token
 81         ::= LPAREN ID!{ tokenName = lexer.GetMatch(span); } COMMA! STRINGLIT!{ tokenInfo = soulcm.scmlg.MakeStrValue(lexer.FileName(), lexer.GetToken(pos)); } RPAREN!
 82         {
 83             return soulcm.scmlg.Token(tokenName, ToUtf8(tokenInfo));
 84         }
 85         ;
 86 
 87     Keywords(var ustring keywordsDeclarationName, var UniquePtr<soulcm.scmlg.Keywords> keywords) : soulcm.scmlg.Keywords*
 88         ::= KEYWORDS ID!{ keywordsDeclarationName = lexer.GetMatch(span); } LBRACE!{ keywords.Reset(new soulcm.scmlg.Keywords(keywordsDeclarationName)); }
 89             (Keyword:keyword{ keywords->Add(keyword); } % COMMA)? RBRACE!
 90         {
 91             return keywords.Release();
 92         }
 93         ;
 94 
 95     Keyword(var ustring kw, var ustring tokenName) : soulcm.scmlg.Keyword*
 96         ::= LPAREN STRINGLIT!{ kw = soulcm.scmlg.MakeStrValue(lexer.FileName(), lexer.GetToken(pos)); } COMMA! ID!{ tokenName = lexer.GetMatch(span); } RPAREN!
 97         {
 98             return new soulcm.scmlg.Keyword(kw, tokenName);
 99         }
100         ;
101 
102     Expressions(var int index, var UniquePtr<soulcm.scmlg.Expressions> expressions) : soulcm.scmlg.Expressions*
103         ::= EXPRESSIONS{ index = 0; expressions.Reset(new soulcm.scmlg.Expressions()); } LBRACE!
104             (Expression(index):expr{ expressions->Add(expr); index = index + 1; })* RBRACE!
105         {
106             return expressions.Release();
107         }
108         ;
109 
110     Expression(int index, var ustring exprName, var int line) : soulcm.scmlg.Expression*
111         ::= ID{ exprName = lexer.GetMatch(span); } ASSIGN ExprString:exprValue!{ line = lexer.GetToken(pos).line; } SEMICOLON!
112         {
113             return new soulcm.scmlg.Expression(index, exprName, exprValue, line);
114         }
115         ;
116 
117     ExprString : ustring
118         ::= STRINGLIT{ return soulcm.scmlg.MakeExprStringValue(lexer.FileName(), lexer.GetToken(pos)); }
119         ;
120 
121     Lexer(ParsingContext* parsingContext, var ustring lexerDeclarationName, var UniquePtr<soulcm.scmlg.Lexer> currentLexer) : soulcm.scmlg.Lexer*
122         ::= LEXER ID!{ lexerDeclarationName = lexer.GetMatch(span); } LBRACE!{ currentLexer.Reset(new soulcm.scmlg.Lexer(u"", lexerDeclarationName)); }
123             (LexerClause(currentLexer.Get(), parsingContext):lexerClause)* RBRACE!
124         {
125             return currentLexer.Release();
126         }
127         ;
128 
129     LexerClause(soulcm.scmlg.Lexer* currentLexer, ParsingContext* parsingContext, var int line)
130         ::= (ExprString:expr{ line = lexer.GetToken(pos).line; } Action:action CompoundStatement(parsingContext):stmt!){ currentLexer->AddStatement(new soulcm.scmlg.LexerStatement(expr, stmt, action, line)); }
131         |   Variables(currentLexer, parsingContext):variables
132         |   Actions(currentLexer, parsingContext):actions
133         ;
134 
135     Variables(soulcm.scmlg.Lexer* currentLexer, ParsingContext* parsingContext)
136         ::= VARIABLES LBRACE! (Variable(parsingContext):variable{ currentLexer->AddVariable(variable); })* RBRACE!
137         ;
138 
139     Variable(ParsingContext* parsingContext, var ustring name) : soulcm.scmlg.Variable*
140         ::= TypeExpr(parsingContext):type ID{ name = lexer.GetMatch(span); } SEMICOLON{ return new soulcm.scmlg.Variable(type, name); }
141         ;
142 
143     Actions(soulcm.scmlg.Lexer* currentLexer, ParsingContext* parsingContext)
144         ::= ACTIONS LBRACE! ((Action:action{ pass = action != -1; } ASSIGN CompoundStatement(parsingContext):stmt!){ currentLexer->AddAction(new soulcm.scmlg.Action(action, stmt)); })* RBRACE!
145         ;
146 
147     Action(var int actionId) : int
148         ::= (DOLLAR LPAREN! INTLIT!{ actionId = soulcm.scmlg.MakeActionIntValue(lexer.FileName(), lexer.GetToken(pos)); } RPAREN!){ return actionId; }
149         |   empty{ return -1; }
150         ;
151 
152     ruleinfo
153     {
154         (LexerFile, "lexer file"), (Declaration, "lexer file declaration"), (ClassMap, "class map declaration"), (Tokens, "tokens declaration"), (Token, "token declaration"),
155         (Keywords, "keywords declaration"), (Keyword, "keyword declaration"), (Expressions, "regular expressions declaration"),
156         (Expression, "regular expression declaration"), (ExprString, "regular expression string"), (Lexer, "lexer declaration"), (LexerClause, "lexer clause"),
157         (Variables, "variables"), (Variable, "variable"), (Actions, "actions"), (Action, "action identifier")
158     }
159 }