parent
73dba8b1db
commit
d84b254716
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.Enums;
|
||||
using Canon.Core.Exceptions;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
|
@ -69,11 +70,11 @@ public interface IGrammarParser
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Run out of token but not accept");
|
||||
throw new GrammarException(stack.Peek().State);
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Failed to analyse input grammar");
|
||||
throw new GrammarException(stack.Peek().State, enumerator.Current);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,71 @@
|
|||
using System.Text;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// 语法分析中引发的异常
|
||||
/// </summary>
|
||||
public class GrammarException : Exception
|
||||
{
|
||||
public GrammarException() { }
|
||||
public override string Message { get; }
|
||||
|
||||
public GrammarException(string message) : base(message) { }
|
||||
/// <summary>
|
||||
/// 语法分析错误时的分析状态
|
||||
/// </summary>
|
||||
public ITransformer CurrentState { get; }
|
||||
|
||||
public GrammarException(string message, Exception innerException) : base(message, innerException) { }
|
||||
/// <summary>
|
||||
/// 语法分析错误时的输入符号
|
||||
/// </summary>
|
||||
public SemanticToken CurrentToken { get; }
|
||||
|
||||
public GrammarException(ITransformer currentState)
|
||||
{
|
||||
CurrentState = currentState;
|
||||
CurrentToken = SemanticToken.End;
|
||||
|
||||
StringBuilder builder = new();
|
||||
builder.Append("Except ");
|
||||
|
||||
foreach (TerminatorBase terminatorBase in ListNextTerminators(CurrentState))
|
||||
{
|
||||
builder.Append('\'').Append(terminatorBase).Append("' ");
|
||||
}
|
||||
|
||||
Message = builder.ToString();
|
||||
}
|
||||
|
||||
public GrammarException(ITransformer currentState, SemanticToken currentToken)
|
||||
{
|
||||
CurrentState = currentState;
|
||||
CurrentToken = currentToken;
|
||||
|
||||
StringBuilder builder = new();
|
||||
builder.Append("Expect ");
|
||||
|
||||
foreach (TerminatorBase terminatorBase in ListNextTerminators(CurrentState))
|
||||
{
|
||||
builder.Append('\'').Append(terminatorBase).Append("',");
|
||||
}
|
||||
|
||||
if (!CurrentToken.Equals(SemanticToken.End))
|
||||
{
|
||||
builder.Append("but '").Append(CurrentToken.LiteralValue).Append("' found.");
|
||||
}
|
||||
|
||||
Message = builder.ToString();
|
||||
}
|
||||
|
||||
private static List<TerminatorBase> ListNextTerminators(ITransformer state)
|
||||
{
|
||||
List<TerminatorBase> result = [];
|
||||
|
||||
result.AddRange(state.ShiftTable.Keys);
|
||||
result.AddRange(state.ReduceTable.Keys);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
71
Canon.Tests/GrammarParserTests/PascalGrammarFailedTests.cs
Normal file
71
Canon.Tests/GrammarParserTests/PascalGrammarFailedTests.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using Canon.Core.Exceptions;
|
||||
using Canon.Tests.Utils;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Canon.Tests.GrammarParserTests;
|
||||
|
||||
public class PascalGrammarFailedTests(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
[Fact]
|
||||
public void StructTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
begin
|
||||
end
|
||||
""";
|
||||
|
||||
CatchException(program);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AssignTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
begin
|
||||
a := 'a';
|
||||
end.
|
||||
""";
|
||||
|
||||
CatchException(program);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StatementTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
begin
|
||||
if a = 1 then
|
||||
doSomething;
|
||||
else
|
||||
doSomething;
|
||||
end.
|
||||
""";
|
||||
|
||||
CatchException(program);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ForTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
begin
|
||||
for a = 1 to 100 do
|
||||
doSomething
|
||||
end.
|
||||
""";
|
||||
|
||||
CatchException(program);
|
||||
}
|
||||
|
||||
private void CatchException(string program)
|
||||
{
|
||||
GrammarException exception = Assert.Throws<GrammarException>(() =>
|
||||
CompilerHelpers.Analyse(program));
|
||||
|
||||
testOutputHelper.WriteLine(exception.Message);
|
||||
}
|
||||
}
|
|
@ -50,22 +50,6 @@ public class PascalGrammarTests
|
|||
Assert.Equal("exFunction", root.Head.ProgramName.LiteralValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SubprogramTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
procedure test;
|
||||
begin
|
||||
end;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||
Assert.Equal("main", root.Head.ProgramName.LiteralValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CharacterTest()
|
||||
{
|
||||
|
@ -94,4 +78,87 @@ public class PascalGrammarTests
|
|||
|
||||
CompilerHelpers.Analyse(program);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultiplyArrayTest()
|
||||
{
|
||||
const string program = """
|
||||
program arrayTest;
|
||||
var a : array [10..100, 0..10] of integer;
|
||||
begin
|
||||
a[10,0] := 1;
|
||||
end.
|
||||
""";
|
||||
|
||||
CompilerHelpers.Analyse(program);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcedureTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
procedure test;
|
||||
begin
|
||||
end;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
CompilerHelpers.Analyse(program);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FunctionTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
function test(a, b : integer) : integer;
|
||||
begin
|
||||
test := 1;
|
||||
end;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
CompilerHelpers.Analyse(program);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ForLoopTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
var i : integer;
|
||||
begin
|
||||
for i := 1 to 100 do
|
||||
begin
|
||||
doSomething(i);
|
||||
end;
|
||||
end.
|
||||
""";
|
||||
|
||||
CompilerHelpers.Analyse(program);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IfConditionTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
begin
|
||||
if 1 = 2 then
|
||||
begin
|
||||
test1;
|
||||
test2 := a;
|
||||
end
|
||||
else
|
||||
begin
|
||||
doSomething;
|
||||
end;
|
||||
end.
|
||||
""";
|
||||
|
||||
CompilerHelpers.Analyse(program);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user