private CharsetGrammar() { var provider = new UnicodeCharSetProvider(); var mapper = new UnicodeUtf16Mapper(false, false); var rx = RegexLexer.CreateRx(mapper); var rxWhitespace = new RxAccept <char>(RxOfSymbol <char> .Extract(rx, RegexLexer.SymWhitespace), SymWhitespace, 0); var rxCharset = new RxAccept <char>(RxOfSymbol <char> .Extract(rx, RegexLexer.SymCharset), SymCharset, 0); var rxRegexCharset = new RxAccept <char>(RxOfSymbol <char> .Extract(rx, RegexLexer.SymRegexCharset), SymRegexCharset, 0); var rxUnion = new RxAccept <char>(RegexMatchSet.FromChars('|', '+').ToInvariant(mapper, provider, true), SymUnion, 0); var rxSubtract = new RxAccept <char>(RegexMatchSet.FromChars('-').ToInvariant(mapper, provider, true), SymSubtract, 0); var rxIntersect = new RxAccept <char>(RegexMatchSet.FromChars('&').ToInvariant(mapper, provider, true), SymIntersect, 0); var rxDifference = new RxAccept <char>(RegexMatchSet.FromChars('^').ToInvariant(mapper, provider, true), SymDifference, 0); var rxNegate = new RxAccept <char>(RegexMatchSet.FromChars('~').ToInvariant(mapper, provider, true), SymNegate, 0); var rxParensOpen = new RxAccept <char>(RegexMatchSet.FromChars('(').ToInvariant(mapper, provider, true), SymParensOpen, 0); var rxParensClose = new RxAccept <char>(RegexMatchSet.FromChars(')').ToInvariant(mapper, provider, true), SymParensClose, 0); var alpha = new AlphabetBuilder <char>( new RxAlternation <char>(rxWhitespace, new RxAlternation <char>(rxCharset, new RxAlternation <char>(rxRegexCharset, new RxAlternation <char>(rxUnion, new RxAlternation <char>(rxSubtract, new RxAlternation <char>(rxIntersect, new RxAlternation <char>(rxDifference, new RxAlternation <char>(rxNegate, new RxAlternation <char>(rxParensOpen, rxParensClose))))))))), Utf16Chars.EOF, Utf16Chars.ValidBmp); var nfa = NfaBuilder <LetterId> .Build(alpha.Expression); var dfa = DfaBuilder <LetterId> .Build(nfa, LetterId.Eof); if (dfa.StartState.Id != default(Id <DfaState <LetterId> >)) { throw new InvalidOperationException($"Internal error: Unexpected DFA start state {dfa.StartState.Id}"); } this.stateMachine = DfaStateMachineEmitter.CreateExpression(dfa, AlphabetMapperEmitter <char> .CreateExpression(alpha)).Compile(); this.table = new LalrTableGenerator(new GrammarBuilder(-2, -1, SymExpression) { { SymUnionExpression, SymExpression, SymUnion, SymNegateExpression }, { SymExpression, SymUnionExpression }, { SymSubtractExpression, SymExpression, SymSubtract, SymNegateExpression }, { SymExpression, SymSubtractExpression }, { SymIntersectExpression, SymExpression, SymIntersect, SymNegateExpression }, { SymExpression, SymIntersectExpression }, { SymDifferenceExpression, SymExpression, SymDifference, SymNegateExpression }, { SymExpression, SymDifferenceExpression }, { SymExpression, SymNegateExpression }, { SymNegateExpression, SymNegate, SymValueExpression }, { SymNegateExpression, SymValueExpression }, { SymValueExpression, SymParensOpen, SymExpression, SymParensClose }, { SymValueExpression, SymCharset }, { SymValueExpression, SymRegexCharset } }) .ComputeTable(); }
public static Expression <Action <TParser, ParserContextBase <TAstNode, TInput, TPosition>, SymbolId, Capture <TInput>, TPosition> > CreateExpression <TParser, TAstNode, TInput, TPosition>(LalrTable table, IParserFragmentEmitter <TParser, TAstNode, TInput, TPosition> fragmentEmitter, Func <SymbolId, string> resolver = null) { var paramParser = Expression.Parameter(typeof(TParser), "parser"); var paramContext = Expression.Parameter(typeof(ParserContextBase <TAstNode, TInput, TPosition>), "context"); var paramTokenSymbolId = Expression.Parameter(typeof(SymbolId), "tokenSymbolId"); var paramTokenValue = Expression.Parameter(typeof(Capture <TInput>), "tokenValue"); var paramPosition = Expression.Parameter(typeof(TPosition), "position"); var varInitialState = Expression.Variable(typeof(ParserState <TAstNode>), "initialState"); var exprCurrentState = Expression.Field(paramContext, Reflect <ParserContext <TAstNode, TInput, TPosition> > .GetField(c => c.currentState)); var lblBreak = Expression.Label("Break"); var lblContinue = Expression.Label("Continue"); var ctor_ParserState = Reflect.GetConstructor(() => new ParserState <TAstNode>(default(TAstNode), default(int), default(ParserState <TAstNode>))); var prop_ParserState_State = Reflect <ParserState <TAstNode> > .GetProperty(s => s.State); var prop_ParserState_Node = Reflect <ParserState <TAstNode> > .GetProperty(s => s.Node); var prop_ParserState_Parent = Reflect <ParserState <TAstNode> > .GetProperty(s => s.Parent); var meth_Accept = Reflect <ParserContext <TAstNode, TInput, TPosition> > .GetMethod(c => c.Accept(default(TAstNode))); var meth_SyntaxError = Reflect <ParserContext <TAstNode, TInput, TPosition> > .GetMethod(c => c.SyntaxError(default(SymbolId), default(Capture <TInput>), default(TPosition), default(IEnumerable <SymbolId>))); Expression DoShift(SymbolId symbolId, ShiftAction action) { return(Expression.Block(typeof(void), Expression.Assign( exprCurrentState, Expression.New( ctor_ParserState, fragmentEmitter.CreateTerminal(symbolId, paramParser, paramTokenValue, paramPosition), Expression.Constant(action.NewState), exprCurrentState)), Expression.Break(lblBreak))); } Expression DoReduce(ReduceSingleAction action) { var varCurrentState = Expression.Variable(typeof(ParserState <TAstNode>), "currentState"); var varsNodes = action.ProductionRule.RuleSymbolIds.Select(s => Expression.Variable(typeof(TAstNode), s.ToString(resolver))).ToArray(); var body = new List <Expression>(varsNodes.Length * 2 + 3); body.Add(Expression.Assign( varCurrentState, exprCurrentState)); for (var i = varsNodes.Length - 1; i >= 0; i--) { body.Add(Expression.Assign( varsNodes[i], Expression.Property( varCurrentState, prop_ParserState_Node))); body.Add(Expression.Assign( varCurrentState, Expression.Property( varCurrentState, prop_ParserState_Parent))); } body.Add(Expression.Assign( exprCurrentState, Expression.New( ctor_ParserState, fragmentEmitter.CreateNonterminal(action.ProductionRule, paramParser, varsNodes), Expression.Switch( Expression.Property( varCurrentState, prop_ParserState_State), Expression.Throw( Expression.New(ctor_InvalidOperationException), typeof(int)), table.Action .Where(a => (a.Value.Type == ActionType.Goto) && (a.Key.Value == action.ProductionRule.ProductionSymbolId)) .Select(a => Expression.SwitchCase( Expression.Constant(((GotoAction)a.Value).NewState), Expression.Constant(a.Key.State) )).ToArray()), varCurrentState))); body.Add(Expression.Continue(lblContinue)); return(Expression.Block(typeof(void), varsNodes.Append(varCurrentState), body)); } Expression DoAccept() { return(Expression.Block(typeof(void), Expression.Call( paramContext, meth_Accept, Expression.Property( exprCurrentState, prop_ParserState_Node)), Expression.Assign( exprCurrentState, Expression.Property( exprCurrentState, prop_ParserState_Parent)), Expression.Break(lblBreak))); } Expression DoThrow() { throw new InvalidOperationException("Internal error: unexpected action type"); } Expression DoSyntaxError() { var varSimulatedState = Expression.Variable(typeof(ParserState <TAstNode>), "simulatedState"); var lblSimulationBreak = Expression.Label(typeof(bool), "simulationBreak"); Expression DoSimulateReduce(ProductionRule rule) { Expression exprNewSimulatedState = Expression.Assign( varSimulatedState, Expression.New( ctor_ParserState, Expression.Default(typeof(TAstNode)), Expression.Switch( Expression.Property( varSimulatedState, prop_ParserState_State), Expression.Break( lblSimulationBreak, Expression.Constant(false), typeof(int)), table.Action .Where(a => (a.Key.Value == rule.ProductionSymbolId) && (a.Value.Type == ActionType.Goto)) .GroupBy(a => ((GotoAction)a.Value).NewState) .Select(g => Expression.SwitchCase( Expression.Constant(g.Key), g.Select(a => Expression.Constant(a.Key.State)))).ToArray()), varSimulatedState)); return(rule.RuleSymbolIds.Count == 0 ? exprNewSimulatedState : Expression.Block( Expression.Assign(varSimulatedState, rule.RuleSymbolIds.Aggregate <SymbolId, Expression>(varSimulatedState, (expression, id) => Expression.Property(expression, prop_ParserState_Parent))), exprNewSimulatedState)); } var varExpectedTokens = Expression.Variable(typeof(List <SymbolId>), "expectedTokens"); var terminalSymbolIds = table.Action .Where(a => (a.Value.Type == ActionType.Accept) || (a.Value.Type == ActionType.Shift)) .Select(a => a.Key.Value) .Distinct() .OrderBy(id => id.ToInt32()) .ToArray(); var body = new List <Expression>(terminalSymbolIds.Length + 2); body.Add(Expression.Assign( varExpectedTokens, Expression.New( ctor_ListOfSymbolId, Expression.Constant(terminalSymbolIds.Length)))); foreach (var symbolId in terminalSymbolIds) { body.Add(Expression.IfThen( Expression.Block(typeof(bool), new[] { varSimulatedState }, Expression.Assign( varSimulatedState, exprCurrentState), Expression.Loop( Expression.Switch(typeof(void), Expression.Property( varSimulatedState, prop_ParserState_State), Expression.Break(lblSimulationBreak, Expression.Constant(false)), null, table.Action .Where(a => (a.Key.Value == symbolId) && (a.Value.Type == ActionType.Reduce)) .GroupBy(a => ((ReduceSingleAction)a.Value).ProductionRule) .Select(g => Expression.SwitchCase( DoSimulateReduce(g.Key), g.Select(a => Expression.Constant(a.Key.State)))) .Append(Expression.SwitchCase( Expression.Break(lblSimulationBreak, Expression.Constant(true)), table.Action .Where(a => (a.Key.Value == symbolId) && ((a.Value.Type == ActionType.Accept) || (a.Value.Type == ActionType.Shift))) .Select(a => Expression.Constant(a.Key.State)) )).ToArray()), lblSimulationBreak)), Expression.Call( varExpectedTokens, meth_ListOfSymbolId_Add, Expression.New( ctor_SymbolId_Int32, Expression.Constant(symbolId.ToInt32()))))); } body.Add(Expression.Convert( varExpectedTokens, typeof(IEnumerable <SymbolId>))); var exprExpectedSymbolIds = Expression.Block(typeof(IEnumerable <SymbolId>), new[] { varExpectedTokens }, body); var exprCustomSyntaxError = fragmentEmitter.SyntaxError(paramParser, paramTokenSymbolId, paramTokenValue, paramPosition, exprExpectedSymbolIds); if (exprCustomSyntaxError?.Type == typeof(bool)) { exprCustomSyntaxError = Expression.IfThen( exprCustomSyntaxError, Expression.Continue(lblContinue)); } return(Expression.Block(typeof(void), Expression.Assign( exprCurrentState, varInitialState), exprCustomSyntaxError ?? Expression.Call( paramContext, meth_SyntaxError, paramTokenSymbolId, paramTokenValue, paramPosition, exprExpectedSymbolIds), Expression.Break(lblBreak))); } return(Expression.Lambda <Action <TParser, ParserContextBase <TAstNode, TInput, TPosition>, SymbolId, Capture <TInput>, TPosition> >( Expression.Block(typeof(void), new[] { varInitialState }, Expression.Assign( varInitialState, exprCurrentState), Expression.Loop( Expression.Block(typeof(void), Expression.Switch( Expression.Property( exprCurrentState, prop_ParserState_State), table.Action .Where(a => (a.Value.Type == ActionType.Shift) || (a.Value.Type == ActionType.Reduce) || (a.Value.Type == ActionType.Accept)) .GroupBy(a => a.Key.State) .Select(g => Expression.SwitchCase( Expression.Switch( Expression.Call( paramTokenSymbolId, meth_SymbolId_ToInt32), g.Select(a => Expression.SwitchCase( a.Value.Type == ActionType.Shift ? DoShift(a.Key.Value, (ShiftAction)a.Value) : a.Value.Type == ActionType.Reduce ? DoReduce((ReduceSingleAction)a.Value) : a.Value.Type == ActionType.Accept ? DoAccept() : DoThrow(), Expression.Constant(a.Key.Value.ToInt32()))).ToArray()), Expression.Constant(g.Key))).ToArray()), DoSyntaxError() ), lblBreak, lblContinue)), paramParser, paramContext, paramTokenSymbolId, paramTokenValue, paramPosition)); }
protected ParserBase(LalrTable table, ParserContextBase <TAstNode, TInput, TPosition> context) { this.table = table; this.context = context; }