parent
67deb0aa2c
commit
792c1d44f1
|
@ -19,6 +19,61 @@ public class GrammarBuilder
|
||||||
|
|
||||||
public HashSet<LrState> Automation { get; } = [];
|
public HashSet<LrState> Automation { get; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 向指定非终结符的FirstSet中添加指定符号的FirstSet
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">指定的非终结符</param>
|
||||||
|
/// <param name="t">指定的符号</param>
|
||||||
|
/// <param name="changed">标记是否改变了FirstSet</param>
|
||||||
|
private void AddFirstSetOfTerminatorBase(NonTerminator target, TerminatorBase t, ref bool changed)
|
||||||
|
{
|
||||||
|
if (t.IsTerminated)
|
||||||
|
{
|
||||||
|
Terminator terminator = (Terminator)t;
|
||||||
|
|
||||||
|
if (FirstSet.TryGetValue(target, out HashSet<Terminator>? firstSet))
|
||||||
|
{
|
||||||
|
if (firstSet.Add(terminator))
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FirstSet.Add(target, [terminator]);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NonTerminator nonTerminator = (NonTerminator)t;
|
||||||
|
|
||||||
|
if (!FirstSet.TryGetValue(nonTerminator, out HashSet<Terminator>? firstSet))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FirstSet.ContainsKey(target))
|
||||||
|
{
|
||||||
|
FirstSet.Add(target, []);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Terminator i in firstSet)
|
||||||
|
{
|
||||||
|
if (i == Terminator.EmptyTerminator)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FirstSet[target].Add(i))
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构建文法中所有非终结符的First集合
|
/// 构建文法中所有非终结符的First集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -34,53 +89,44 @@ public class GrammarBuilder
|
||||||
{
|
{
|
||||||
foreach (List<TerminatorBase> expression in pair.Value)
|
foreach (List<TerminatorBase> expression in pair.Value)
|
||||||
{
|
{
|
||||||
// TODO: 对于空产生式直接跳过处理是正确的吗
|
TerminatorBase expressionHead = expression.First();
|
||||||
TerminatorBase? expressionHead = expression.FirstOrDefault();
|
AddFirstSetOfTerminatorBase(pair.Key, expressionHead, ref changed);
|
||||||
if (expressionHead is null)
|
|
||||||
|
// 处理空产生式
|
||||||
|
for (int i = 0; i < expression.Count; i++)
|
||||||
{
|
{
|
||||||
continue;
|
if (!expression[i].IsTerminated)
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (expressionHead.IsTerminated)
|
|
||||||
{
|
|
||||||
// 产生式的第一个字符是终结符
|
|
||||||
// 将这个终结符加入该非终结符的First集合
|
|
||||||
Terminator terminator = (Terminator)expressionHead;
|
|
||||||
|
|
||||||
if (FirstSet.TryAdd(pair.Key, [terminator]))
|
|
||||||
{
|
{
|
||||||
changed = true;
|
NonTerminator nonTerminator = (NonTerminator)expression[i];
|
||||||
|
|
||||||
|
// 可以推出空产生式
|
||||||
|
// 则将下一个符号的FirstSet加入该符号的集合中
|
||||||
|
if (!FirstSet.TryGetValue(nonTerminator, out HashSet<Terminator>? firstSet))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firstSet.Contains(Terminator.EmptyTerminator))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i + 1 < expression.Count)
|
||||||
|
{
|
||||||
|
// 还有下一个符号
|
||||||
|
// 就把下一个符号的FirstSet加入
|
||||||
|
AddFirstSetOfTerminatorBase(pair.Key, expression[i + 1], ref changed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 没有下一个符号了
|
||||||
|
// 就需要加入空串
|
||||||
|
AddFirstSetOfTerminatorBase(pair.Key, Terminator.EmptyTerminator, ref changed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (FirstSet[pair.Key].Add(terminator))
|
break;
|
||||||
{
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NonTerminator nonTerminator = (NonTerminator)expressionHead;
|
|
||||||
// 产生式的第一个字符是非终结符
|
|
||||||
// 将该非终结符的结果合并到该
|
|
||||||
if (FirstSet.TryGetValue(nonTerminator, out HashSet<Terminator>? value))
|
|
||||||
{
|
|
||||||
foreach (Terminator first in value)
|
|
||||||
{
|
|
||||||
if (FirstSet.TryAdd(pair.Key, [first]))
|
|
||||||
{
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (FirstSet[pair.Key].Add(first))
|
|
||||||
{
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,4 +59,15 @@ public class GenerateParserTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubprogramDeclarationsFirstSetTest()
|
||||||
|
{
|
||||||
|
Assert.True(_builder.FirstSet.TryGetValue(
|
||||||
|
new NonTerminator(NonTerminatorType.SubprogramDeclarations), out HashSet<Terminator>? firstSet));
|
||||||
|
Assert.NotNull(firstSet);
|
||||||
|
Assert.Contains(Terminator.EmptyTerminator, firstSet);
|
||||||
|
Assert.Contains(new Terminator(KeywordType.Procedure), firstSet);
|
||||||
|
Assert.Contains(new Terminator(KeywordType.Function), firstSet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -68,14 +68,23 @@ public class PascalGrammarTests
|
||||||
Assert.Equal("exFunction", root.Head.ProgramName.LiteralValue);
|
Assert.Equal("exFunction", root.Head.ProgramName.LiteralValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IGrammarParser GenerateGrammarParser()
|
[Fact]
|
||||||
|
public void SubprogramTest()
|
||||||
{
|
{
|
||||||
GrammarBuilder builder = new()
|
const string program = """
|
||||||
{
|
program main;
|
||||||
Generators = PascalGrammar.Grammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator)
|
procedure test;
|
||||||
};
|
begin
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
Grammar grammar = builder.Build();
|
Lexer lexer = new(program);
|
||||||
return grammar.ToGrammarParser();
|
List<SemanticToken> tokens = lexer.Tokenize();
|
||||||
|
tokens.Add(SemanticToken.End);
|
||||||
|
|
||||||
|
ProgramStruct root = _parser.Analyse(tokens);
|
||||||
|
Assert.Equal("main", root.Head.ProgramName.LiteralValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user