/// <summary> /// 将正则表达式转换为 NFA。 /// </summary> /// <param name="grammar">语法分析的语法。</param> /// <param name="useTrailing">是否使用了向前看符号。</param> /// <returns>构造得到的 NFA。</returns> private static Nfa BuildNfa(Grammar <T> grammar, out bool useTrailing) { int contextCnt = grammar.Contexts.Count; // 将多个上下文的规则放入一个 NFA 中,但起始状态不同。 Nfa nfa = new Nfa(); for (int i = 0; i < contextCnt; i++) { // 为每个上下文创建自己的起始状态,普通规则的起始状态。 nfa.NewState(); // 行首规则的起始状态。 nfa.NewState(); } useTrailing = false; foreach (Terminal <T> sym in grammar.Terminals) { if (sym.RegularExpression is EndOfFileExp) { continue; } sym.RegularExpression.BuildNfa(nfa); nfa.TailState.SymbolIndex = sym.Index; // 是否是行首限定的。 bool isBeginningOfLine = false; AnchorExp anchorExp = sym.RegularExpression as AnchorExp; if (anchorExp != null) { if (anchorExp.BeginningOfLine) { isBeginningOfLine = true; } if (anchorExp.TrailingHeadState != null) { // 设置向前看状态类型。 anchorExp.TrailingHeadState.SymbolIndex = sym.Index; useTrailing = true; } } foreach (LexerContext context in sym.Context) { if (isBeginningOfLine) { // 行首限定规则。 nfa[context.Index * 2 + 1].Add(nfa.HeadState); } else { // 普通规则。 nfa[context.Index * 2].Add(nfa.HeadState); nfa[context.Index * 2 + 1].Add(nfa.HeadState); } } } return(nfa); }
/// <summary> /// 填充行首匹配和向前看的数据。 /// </summary> /// <param name="grammar">词法分析器使用的语法。</param> private void FillTrailing(Grammar <T> grammar) { bool variableTrailing = false; this.containsBeginningOfLineRule = false; foreach (Terminal <T> sym in grammar.Terminals) { AnchorExp exp = sym.RegularExpression as AnchorExp; if (exp != null) { if (exp.BeginningOfLine == true) { this.containsBeginningOfLineRule = true; } if (exp.TrailingExpression != null) { int len = exp.TrailingExpression.Length; if (len != -1) { this.symbols[sym.Index].Trailing = -len; } else { len = exp.InnerExpression.Length; if (len != -1) { this.symbols[sym.Index].Trailing = len; } else { this.symbols[sym.Index].Trailing = 0; variableTrailing = true; } } } } } if (variableTrailing) { this.trailingType = TrailingType.Variable; } else { this.trailingType = TrailingType.Fixed; } }