feat: 按照open_set中的示例调整语法 (#71)

添加了构建LR分析表冲突的报错

Reviewed-on: PostGuard/Canon#71
This commit is contained in:
jackfiled 2024-05-01 21:06:27 +08:00
parent feddbff205
commit 6130adfa7c
32 changed files with 1382 additions and 985 deletions

View File

@ -1,8 +1,5 @@
name: Integration Test name: Integration Test
on: on: [push]
push:
branches:
- master
jobs: jobs:
Open-Set-Test: Open-Set-Test:
@ -18,8 +15,10 @@ jobs:
save-always: true save-always: true
- name: Build binary file - name: Build binary file
run: | run: |
cd ./Canon.Console
dotnet publish dotnet publish
cp ./Canon.Console/bin/Release/net8.0/linux-x64/publish/Canon.Console ./pacss cd ..
cp ./Canon.Console/bin/Release/net8.0/linux-x64/publish/Canon.Console ./pascc
- name: Build open set binary - name: Build open set binary
run: | run: |
python scripts/integration_test.py run python scripts/integration_test.py run

3
.gitignore vendored
View File

@ -485,3 +485,6 @@ $RECYCLE.BIN/
# Database Source File # Database Source File
*.db *.db
# Pascall C Compiler
pascc

View File

@ -62,7 +62,9 @@ public enum KeywordType
Not, Not,
Mod, Mod,
And, And,
Or Or,
True,
False
} }
public enum OperatorType public enum OperatorType
@ -99,11 +101,3 @@ public enum StateType
Unknown, Unknown,
Done Done
} }
public enum BasicIdType
{
Int,
Real,
Char,
Bool
}

View File

@ -0,0 +1,6 @@
namespace Canon.Core.Exceptions;
public class ReduceAndShiftConflictException : Exception
{
}

View File

@ -0,0 +1,17 @@
using Canon.Core.GrammarParser;
namespace Canon.Core.Exceptions;
public class ReduceConflictException(LrState originState, Terminator lookAhead, NonTerminator left1, NonTerminator left2)
: Exception
{
public LrState OriginState { get; } = originState;
public Terminator LookAhead { get; } = lookAhead;
public NonTerminator Left1 { get; } = left1;
public NonTerminator Left2 { get; } = left2;
public override string Message => "Reduce Conflict!";
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,6 @@
using Canon.Core.Abstractions; using Canon.Core.Abstractions;
using Canon.Core.Enums;
using Canon.Core.Exceptions;
namespace Canon.Core.GrammarParser; namespace Canon.Core.GrammarParser;
@ -45,13 +47,23 @@ public class Grammar
{ {
if (expression.Pos == expression.Right.Count) if (expression.Pos == expression.Right.Count)
{ {
transformer.ReduceTable.TryAdd(expression.LookAhead, new ReduceInformation( if (transformer.ShiftTable.ContainsKey(expression.LookAhead))
expression.Right.Count, expression.Left)); {
throw new ReduceAndShiftConflictException();
}
if (!transformer.ReduceTable.TryAdd(expression.LookAhead,
new ReduceInformation(expression.Right.Count, expression.Left)))
{
// 发生归约-归约冲突
throw new ReduceConflictException(state, expression.LookAhead, expression.Left,
transformer.ReduceTable[expression.LookAhead].Left);
}
} }
} }
// 生成移进的迁移表 // 生成移进的迁移表
foreach (KeyValuePair<TerminatorBase,LrState> pair in state.Transformer) foreach (KeyValuePair<TerminatorBase, LrState> pair in state.Transformer)
{ {
ITransformer targetTransformer; ITransformer targetTransformer;
if (transformers.TryGetValue(pair.Value, out Transformer? oldTransformer2)) if (transformers.TryGetValue(pair.Value, out Transformer? oldTransformer2))
@ -64,7 +76,19 @@ public class Grammar
transformers.Add(pair.Value, newTransformer); transformers.Add(pair.Value, newTransformer);
targetTransformer = newTransformer; targetTransformer = newTransformer;
} }
transformer.ShiftTable.TryAdd(pair.Key, targetTransformer);
// 检测移进-归约冲突
if (pair.Key.IsTerminated)
{
Terminator terminator = (Terminator)pair.Key;
// hack 对于ElsePart的移进-归约冲突
if (terminator != new Terminator(KeywordType.Else) && transformer.ReduceTable.ContainsKey(terminator))
{
throw new ReduceAndShiftConflictException();
}
}
transformer.ShiftTable.Add(pair.Key, targetTransformer);
} }
} }

View File

@ -101,7 +101,7 @@ public static class PascalGrammar
] ]
}, },
{ {
// ConstValue -> +num | -num | num | 'letter' // ConstValue -> +num | -num | num | 'letter' | true | false
new NonTerminator(NonTerminatorType.ConstValue), [ new NonTerminator(NonTerminatorType.ConstValue), [
[ [
new Terminator(OperatorType.Plus), Terminator.NumberTerminator new Terminator(OperatorType.Plus), Terminator.NumberTerminator
@ -114,6 +114,12 @@ public static class PascalGrammar
], ],
[ [
Terminator.CharacterTerminator, Terminator.CharacterTerminator,
],
[
new Terminator(KeywordType.True)
],
[
new Terminator(KeywordType.False)
] ]
] ]
}, },
@ -245,6 +251,10 @@ public static class PascalGrammar
[ [
Terminator.EmptyTerminator, Terminator.EmptyTerminator,
], ],
[
new Terminator(DelimiterType.LeftParenthesis),
new Terminator(DelimiterType.RightParenthesis)
],
[ [
new Terminator(DelimiterType.LeftParenthesis), new Terminator(DelimiterType.LeftParenthesis),
new NonTerminator(NonTerminatorType.ParameterList), new NonTerminator(NonTerminatorType.ParameterList),
@ -334,13 +344,10 @@ public static class PascalGrammar
{ {
// Statement -> ε // Statement -> ε
// | Variable AssignOp Expression // | Variable AssignOp Expression
// | FuncId AssignOp Expression
// | ProcedureCall // | ProcedureCall
// | CompoundStatement // | CompoundStatement
// | if Expression then Statement ElsePart // | if Expression then Statement ElsePart
// | for id AssignOp Expression to Expression do Statement // | for id AssignOp Expression to Expression do Statement
// | read ( VariableList )
// | write( ExpressionList )
// 注意这里 read 和 write 作为普通的函数调用处理了 // 注意这里 read 和 write 作为普通的函数调用处理了
// 因此下面并没有单独声明 // 因此下面并没有单独声明
new NonTerminator(NonTerminatorType.Statement), [ new NonTerminator(NonTerminatorType.Statement), [
@ -354,12 +361,6 @@ public static class PascalGrammar
new Terminator(OperatorType.Assign), new Terminator(OperatorType.Assign),
new NonTerminator(NonTerminatorType.Expression) new NonTerminator(NonTerminatorType.Expression)
], ],
[
// FuncId AssignOp Expression
Terminator.IdentifierTerminator,
new Terminator(OperatorType.Assign),
new NonTerminator(NonTerminatorType.Expression)
],
[ [
// ProcedureCall // ProcedureCall
new NonTerminator(NonTerminatorType.ProcedureCall) new NonTerminator(NonTerminatorType.ProcedureCall)
@ -426,11 +427,16 @@ public static class PascalGrammar
] ]
}, },
{ {
// ProcedureCall -> id | id ( ExpressionList ) // ProcedureCall -> id | id() | id ( ExpressionList )
new NonTerminator(NonTerminatorType.ProcedureCall), [ new NonTerminator(NonTerminatorType.ProcedureCall), [
[ [
Terminator.IdentifierTerminator, Terminator.IdentifierTerminator,
], ],
[
Terminator.IdentifierTerminator,
new Terminator(DelimiterType.LeftParenthesis),
new Terminator(DelimiterType.RightParenthesis)
],
[ [
Terminator.IdentifierTerminator, Terminator.IdentifierTerminator,
new Terminator(DelimiterType.LeftParenthesis), new Terminator(DelimiterType.LeftParenthesis),
@ -506,9 +512,13 @@ public static class PascalGrammar
{ {
// Factor -> num | Variable // Factor -> num | Variable
// | ( Expression ) // | ( Expression )
// | id ( ExpressionList ) // | id ()
// | id (ExpressionList)
// | not Factor // | not Factor
// | minus Factor // | - Factor
// | + Factor
// | true
// | false
new NonTerminator(NonTerminatorType.Factor), [ new NonTerminator(NonTerminatorType.Factor), [
[ [
Terminator.NumberTerminator, Terminator.NumberTerminator,
@ -521,6 +531,11 @@ public static class PascalGrammar
new NonTerminator(NonTerminatorType.Expression), new NonTerminator(NonTerminatorType.Expression),
new Terminator(DelimiterType.RightParenthesis) new Terminator(DelimiterType.RightParenthesis)
], ],
[
Terminator.IdentifierTerminator,
new Terminator(DelimiterType.LeftParenthesis),
new Terminator(DelimiterType.RightParenthesis)
],
[ [
Terminator.IdentifierTerminator, Terminator.IdentifierTerminator,
new Terminator(DelimiterType.LeftParenthesis), new Terminator(DelimiterType.LeftParenthesis),
@ -534,6 +549,16 @@ public static class PascalGrammar
[ [
new Terminator(OperatorType.Minus), new Terminator(OperatorType.Minus),
new NonTerminator(NonTerminatorType.Factor) new NonTerminator(NonTerminatorType.Factor)
],
[
new Terminator(OperatorType.Plus),
new NonTerminator(NonTerminatorType.Factor)
],
[
new Terminator(KeywordType.True)
],
[
new Terminator(KeywordType.False)
] ]
] ]
}, },

View File

@ -31,7 +31,9 @@ public static class LexRules
{ "not", KeywordType.Not }, { "not", KeywordType.Not },
{ "mod", KeywordType.Mod }, { "mod", KeywordType.Mod },
{ "and", KeywordType.And }, { "and", KeywordType.And },
{ "or", KeywordType.Or } { "or", KeywordType.Or },
{ "true", KeywordType.True },
{ "false", KeywordType.False }
}; };
public static bool GetKeywordTypeByKeywprd(string keyword, out KeywordType type) public static bool GetKeywordTypeByKeywprd(string keyword, out KeywordType type)

View File

@ -1,4 +1,5 @@
using System.Globalization; using System.Globalization;
using Canon.Core.Abstractions;
using Canon.Core.CodeGenerators; using Canon.Core.CodeGenerators;
using Canon.Core.Enums; using Canon.Core.Enums;
using Canon.Core.LexicalParser; using Canon.Core.LexicalParser;
@ -7,7 +8,7 @@ using BasicType = Canon.Core.SyntaxNodes.BasicType;
namespace Canon.Core.SemanticParser; namespace Canon.Core.SemanticParser;
public class CCodeGenerateVisitor : TypeCheckVisitor public class CCodeGenerateVisitor(ICompilerLogger? logger = null) : TypeCheckVisitor(logger)
{ {
public CCodeBuilder Builder { get; } = new(); public CCodeBuilder Builder { get; } = new();
@ -142,7 +143,7 @@ public class CCodeGenerateVisitor : TypeCheckVisitor
Builder.AddString("("); Builder.AddString("(");
List<string> parametersInfo = new(); List<string> parametersInfo = new();
foreach (List<Symbol> children in _valueParameters) foreach (List<Symbol> children in ValueParameters)
{ {
foreach (Symbol symbol in children.AsEnumerable().Reverse()) foreach (Symbol symbol in children.AsEnumerable().Reverse())
{ {
@ -432,10 +433,6 @@ public class CCodeGenerateVisitor : TypeCheckVisitor
token.ParseAsReal().ToString(CultureInfo.InvariantCulture); token.ParseAsReal().ToString(CultureInfo.InvariantCulture);
Builder.AddString(num); Builder.AddString(num);
}; };
factor.OnProcedureCallGenerator += (_, _) =>
{
Builder.AddString(")");
};
factor.OnNotGenerator += (_, _) => factor.OnNotGenerator += (_, _) =>
{ {
Builder.AddString(")"); Builder.AddString(")");
@ -449,25 +446,10 @@ public class CCodeGenerateVisitor : TypeCheckVisitor
public override void PreVisit(Factor factor) public override void PreVisit(Factor factor)
{ {
base.PreVisit(factor); base.PreVisit(factor);
factor.OnProcedureCallGenerator += (_, e) =>
{
Builder.AddString(e.ProcedureName.IdentifierName + "(");
SymbolTable.TryGetParent(out var parentTable);
parentTable ??= SymbolTable;
parentTable.TryGetSymbol(e.ProcedureName.IdentifierName, out var symbol);
if (symbol == null)
{
return;
}
e.Parameters.ParameterTypes.AddRange(symbol.SymbolType.Convert<PascalFunctionType>().Parameters);
e.Parameters.IsParamList = true;
e.Parameters.Expression.LastParam = true;
};
factor.OnNotGenerator += (_, _) => factor.OnNotGenerator += (_, _) =>
{ {
Builder.AddString("(!"); Builder.AddString("(~");
}; };
factor.OnUminusGenerator += (_, _) => factor.OnUminusGenerator += (_, _) =>
{ {

View File

@ -8,6 +8,11 @@ public class PascalFunctionType(List<PascalParameterType> parameters, PascalType
public PascalType ReturnType { get; } = returnType; public PascalType ReturnType { get; } = returnType;
/// <summary>
/// Pascal核心库函数的类型
/// </summary>
public static PascalFunctionType CoreFuntionType => new PascalFunctionType([], PascalBasicType.Void);
public override string TypeName public override string TypeName
{ {
get get

View File

@ -1,4 +1,5 @@
using Canon.Core.Abstractions; using System.Diagnostics.CodeAnalysis;
using Canon.Core.Abstractions;
using Canon.Core.Enums; using Canon.Core.Enums;
using Canon.Core.LexicalParser; using Canon.Core.LexicalParser;
using Canon.Core.SyntaxNodes; using Canon.Core.SyntaxNodes;
@ -7,8 +8,11 @@ using Expression = Canon.Core.SyntaxNodes.Expression;
namespace Canon.Core.SemanticParser; namespace Canon.Core.SemanticParser;
public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : SyntaxNodeVisitor public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisitor
{ {
/// <summary>
/// 当前遍历阶段的符号表
/// </summary>
public SymbolTable SymbolTable { get; private set; } = new(); public SymbolTable SymbolTable { get; private set; } = new();
/// <summary> /// <summary>
@ -91,88 +95,63 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
} }
}; };
// factor -> true | false
factor.OnBooleanGenerator += (_, _) => { factor.FactorType = PascalBasicType.Boolean; };
// factor -> variable // factor -> variable
factor.OnVariableGenerator += (_, e) => { factor.FactorType = e.Variable.VariableType; }; factor.OnVariableGenerator += (_, e) => { factor.FactorType = e.Variable.VariableType; };
// factor -> (expression) // factor -> (expression)
factor.OnParethnesisGenerator += (_, e) => { factor.FactorType = e.Expression.ExpressionType; }; factor.OnParethnesisGenerator += (_, e) => { factor.FactorType = e.Expression.ExpressionType; };
// factor -> id (expression_list) // factor -> id ()
factor.OnProcedureCallGenerator += (_, e) => factor.OnNoParameterProcedureCallGenerator += (_, e) =>
{ {
if (!SymbolTable.TryGetSymbol(e.ProcedureName.IdentifierName, out Symbol? procedure)) if (ValidateProcedureCall(e.ProcedureName, [], out PascalFunctionType? functionType))
{ {
IsError = true; if (functionType.ReturnType != PascalBasicType.Void)
logger?.LogError("Procedure '{}' does not define.", e.ProcedureName.IdentifierName);
return;
}
PascalFunctionType? functionType = procedure.SymbolType as PascalFunctionType;
if (functionType is null)
{
if (SymbolTable.TryGetParent(out SymbolTable? parent))
{ {
if (parent.TryGetSymbol(e.ProcedureName.IdentifierName, out procedure)) factor.FactorType = functionType.ReturnType;
{
functionType = procedure.SymbolType as PascalFunctionType;
}
}
}
if (functionType is null)
{
IsError = true;
logger?.LogError("'{}' is not call able.", e.ProcedureName.IdentifierName);
return;
}
if (functionType.ReturnType == PascalBasicType.Void)
{
IsError = true;
logger?.LogError("Procedure '{}' returns void.", e.ProcedureName.IdentifierName);
return;
}
factor.FactorType = functionType.ReturnType;
if (e.Parameters.Expressions.Count != functionType.Parameters.Count)
{
IsError = true;
logger?.LogError("Procedure '{}' expects {} parameters but {} provided.",
e.ProcedureName.IdentifierName,
functionType.Parameters.Count,
e.Parameters.Expressions.Count);
return;
}
foreach ((Expression expression, PascalParameterType parameterType) in e.Parameters.Expressions.Zip(
functionType.Parameters))
{
if (expression.ExpressionType != parameterType.ParameterType)
{
IsError = true;
logger?.LogError("Parameter expect '{}' but '{}'",
parameterType.ParameterType.TypeName, expression.ExpressionType);
return; return;
} }
else
{
IsError = true;
logger?.LogError("The procedure '{}' returns void.", e.ProcedureName.IdentifierName);
}
} }
factor.FactorType = PascalBasicType.Void;
}; };
// factor -> factor // factor -> id ( ExpressionList)
factor.OnNotGenerator += (_, e) => factor.OnProcedureCallGenerator += (_, e) =>
{ {
if (e.Factor.FactorType != PascalBasicType.Boolean) if (ValidateProcedureCall(e.ProcedureName, e.Parameters.Expressions, out PascalFunctionType? functionType))
{ {
IsError = true; if (functionType.ReturnType != PascalBasicType.Void)
logger?.LogError("The boolean type is expected."); {
return; factor.FactorType = functionType.ReturnType;
return;
}
else
{
IsError = true;
logger?.LogError("The procedure '{}' returns void.", e.ProcedureName.IdentifierName);
}
} }
factor.FactorType = PascalBasicType.Boolean; factor.FactorType = PascalBasicType.Void;
}; };
// factor -> not factor
factor.OnNotGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; };
// factor -> uminus factor // factor -> uminus factor
factor.OnUminusGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; }; factor.OnUminusGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; };
// factor -> plus factor
factor.OnPlusGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; };
} }
public override void PostVisit(Term term) public override void PostVisit(Term term)
@ -308,7 +287,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
/// <summary> /// <summary>
/// 多个ValueParameter下定义的参数列表 /// 多个ValueParameter下定义的参数列表
/// </summary> /// </summary>
protected readonly List<List<Symbol>> _valueParameters = []; protected readonly List<List<Symbol>> ValueParameters = [];
public override void PreVisit(Subprogram subprogram) public override void PreVisit(Subprogram subprogram)
{ {
@ -334,7 +313,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
base.PreVisit(subprogramHead); base.PreVisit(subprogramHead);
_parameters = null; _parameters = null;
_valueParameters.Clear(); ValueParameters.Clear();
} }
public override void PostVisit(SubprogramHead subprogramHead) public override void PostVisit(SubprogramHead subprogramHead)
@ -351,7 +330,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
// 正序遍历_valueParameter // 正序遍历_valueParameter
// 倒序遍历其中的列表 // 倒序遍历其中的列表
foreach (List<Symbol> children in _valueParameters) foreach (List<Symbol> children in ValueParameters)
{ {
foreach (Symbol symbol in children.AsEnumerable().Reverse()) foreach (Symbol symbol in children.AsEnumerable().Reverse())
{ {
@ -397,7 +376,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
valueParameter.IdentifierList.IsProcedure = true; valueParameter.IdentifierList.IsProcedure = true;
_parameters = []; _parameters = [];
_valueParameters.Add(_parameters); ValueParameters.Add(_parameters);
if (valueParameter.IsReference) if (valueParameter.IsReference)
{ {
valueParameter.IdentifierList.IsReference = true; valueParameter.IdentifierList.IsReference = true;
@ -496,72 +475,22 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
public override void PostVisit(ProcedureCall procedureCall) public override void PostVisit(ProcedureCall procedureCall)
{ {
base.PostVisit(procedureCall); base.PostVisit(procedureCall);
// 查看当前符号表中procedureId是否注册
if (!SymbolTable.TryGetSymbol(procedureCall.ProcedureId.IdentifierName, out Symbol? procedure))
{
// id没有定义
IsError = true;
logger?.LogError("procedure '{}' is not defined.", procedureCall.ProcedureId.LiteralValue);
return;
}
if (procedure.SymbolType is not PascalFunctionType functionType)
{
// id不是函数类型,要找父符号表
if (!SymbolTable.TryGetParent(out SymbolTable? parent))
{
// 没找到父符号表,说明这个id是非函数变量
IsError = true;
logger?.LogError("Identifier '{}' is not a call-able.", procedureCall.ProcedureId.LiteralValue);
return;
}
if (!parent.TryGetSymbol(procedureCall.ProcedureId.IdentifierName, out Symbol? procedureParent))
{
// 找到父符号表但没有找到该id,说明这个id没定义
IsError = true;
logger?.LogError("procedure '{}' is not defined.", procedureCall.ProcedureId.LiteralValue);
return;
}
// 父符号表中找到该id
if (procedureParent.SymbolType is not PascalFunctionType functionTypeParent)
{
// 该符号不是函数类型
IsError = true;
logger?.LogError("Identifier '{}' is not a call-able.", procedureParent.SymbolName);
return;
}
// 该符号是函数类型,赋给procedure
procedure = procedureParent;
functionType = functionTypeParent;
}
procedureCall.OnParameterGenerator += (_, e) => procedureCall.OnParameterGenerator += (_, e) =>
{ {
// 检查procedure输入参数个数是否相符 if (ValidateProcedureCall(procedureCall.ProcedureId, e.Parameters.Expressions,
if (e.Parameters.Expressions.Count != functionType.Parameters.Count) out PascalFunctionType? functionType))
{ {
IsError = true; procedureCall.ReturnType = functionType.ReturnType;
logger?.LogError("Procedure '{}' expects {} parameters but {} provided.",
procedure.SymbolName,
functionType.Parameters.Count,
e.Parameters.Expressions.Count);
return;
} }
};
// 检查每个参数的类型与procedure参数定义类型是否相符 procedureCall.OnNoParameterGenerator += (_, _) =>
foreach ((Expression expression, PascalParameterType parameterType) in e.Parameters.Expressions.Zip( {
functionType.Parameters)) if (ValidateProcedureCall(procedureCall.ProcedureId, [],
out PascalFunctionType? functionType))
{ {
if (expression.ExpressionType != parameterType.ParameterType) procedureCall.ReturnType = functionType.ReturnType;
{
IsError = true;
logger?.LogError("Parameter expect '{}' but '{}'",
parameterType.ParameterType.TypeName, expression.ExpressionType);
return;
}
} }
}; };
} }
@ -569,10 +498,20 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
public override void PostVisit(Variable variable) public override void PostVisit(Variable variable)
{ {
base.PostVisit(variable); base.PostVisit(variable);
if (SymbolTable.TryGetSymbol(variable.Identifier.IdentifierName, out Symbol? id)) if (SymbolTable.TryGetSymbol(variable.Identifier.IdentifierName, out Symbol? id))
{ {
variable.VariableType = id.SymbolType; variable.VariableType = id.SymbolType;
if (variable.VariableType is PascalFunctionType functionType)
{
// 考虑不带参数的函数调用
if (functionType.Parameters.Count == 0 && functionType.ReturnType != PascalBasicType.Void)
{
variable.VariableType = functionType.ReturnType;
}
}
for (int i = 0; i < variable.VarPart.IndexCount; i++) for (int i = 0; i < variable.VarPart.IndexCount; i++)
{ {
if (variable.VariableType is PascalArrayType arrayType) if (variable.VariableType is PascalArrayType arrayType)
@ -614,4 +553,90 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
identifierVarPart.IndexCount = e.IndexParameters.Expressions.Count; identifierVarPart.IndexCount = e.IndexParameters.Expressions.Count;
}; };
} }
private static readonly HashSet<string> s_pascalCoreProcedures =
[
"read",
"readln",
"write",
"writeln"
];
/// <summary>
/// 验证过程调用的类型正确性
/// </summary>
/// <param name="procedureName">过程的名称</param>
/// <param name="parameters">调用过程的参数</param>
/// <param name="functionType">过程的类型</param>
/// <returns>是否正确进行调用</returns>
private bool ValidateProcedureCall(IdentifierSemanticToken procedureName, List<Expression> parameters,
[NotNullWhen(true)] out PascalFunctionType? functionType)
{
if (s_pascalCoreProcedures.Contains(procedureName.IdentifierName))
{
functionType = PascalFunctionType.CoreFuntionType;
return true;
}
if (!SymbolTable.TryGetSymbol(procedureName.IdentifierName, out Symbol? symbol))
{
functionType = null;
IsError = true;
logger?.LogError("Identifier '{}' is not defined.", procedureName.IdentifierName);
return false;
}
PascalFunctionType? targetFunctionType = null;
if (symbol.SymbolType is not PascalFunctionType pascalFunctionType)
{
// 尝试查询父级符号表
// 处理过程定义中的递归调用问题
if (SymbolTable.TryGetParent(out SymbolTable? parent))
{
if (parent.TryGetSymbol(procedureName.IdentifierName, out Symbol? parentSymbol))
{
if (parentSymbol.SymbolType is PascalFunctionType parentFunctionType)
{
targetFunctionType = parentFunctionType;
}
}
}
}
else
{
targetFunctionType = pascalFunctionType;
}
if (targetFunctionType is null)
{
functionType = null;
IsError = true;
logger?.LogError("Identifier '{}' is not call-able.", procedureName.IdentifierName);
return false;
}
if (targetFunctionType.Parameters.Count != parameters.Count)
{
functionType = null;
IsError = true;
logger?.LogError("Procedure '{}' needs {} parameters but provide {} parameters.",
procedureName.IdentifierName,
targetFunctionType.Parameters.Count, parameters.Count);
return false;
}
foreach ((Expression expression, PascalParameterType parameterType) in parameters.Zip(targetFunctionType
.Parameters))
{
if (expression.ExpressionType != parameterType.ParameterType)
{
IsError = true;
logger?.LogError("Parameter expect '{}' but '{}' is provided.",
parameterType.ParameterType, expression.ExpressionType);
}
}
functionType = targetFunctionType;
return true;
}
} }

View File

@ -38,28 +38,6 @@ public class BasicType : NonTerminatedSyntaxNode
} }
} }
public override void GenerateCCode(CCodeBuilder builder)
{
var keywordType = Children[0].Convert<TerminatedSyntaxNode>().Token
.Convert<KeywordSemanticToken>().KeywordType;
switch (keywordType)
{
case KeywordType.Integer:
builder.AddString(" int");
break;
case KeywordType.Real:
builder.AddString(" double");
break;
case KeywordType.Boolean:
builder.AddString(" bool");
break;
case KeywordType.Character:
builder.AddString(" char");
break;
}
}
public override void PreVisit(SyntaxNodeVisitor visitor) public override void PreVisit(SyntaxNodeVisitor visitor)
{ {
visitor.PreVisit(this); visitor.PreVisit(this);

View File

@ -6,12 +6,12 @@ using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public class OnSimpleExpressionGeneratorEventArgs : EventArgs public class SimpleExpressionGeneratorEventArgs : EventArgs
{ {
public required SimpleExpression SimpleExpression { get; init; } public required SimpleExpression SimpleExpression { get; init; }
} }
public class OnRelationGeneratorEventArgs : EventArgs public class RelationGeneratorEventArgs : EventArgs
{ {
public required SimpleExpression Left { get; init; } public required SimpleExpression Left { get; init; }
@ -76,12 +76,12 @@ public class Expression : NonTerminatedSyntaxNode
/// <summary> /// <summary>
/// 直接赋值产生式的事件 /// 直接赋值产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnSimpleExpressionGeneratorEventArgs>? OnSimpleExpressionGenerator; public event EventHandler<SimpleExpressionGeneratorEventArgs>? OnSimpleExpressionGenerator;
/// <summary> /// <summary>
/// 关系产生式的事件 /// 关系产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnRelationGeneratorEventArgs>? OnRelationGenerator; public event EventHandler<RelationGeneratorEventArgs>? OnRelationGenerator;
private PascalType? _expressionType; private PascalType? _expressionType;
@ -111,14 +111,14 @@ public class Expression : NonTerminatedSyntaxNode
{ {
if (Children.Count == 1) if (Children.Count == 1)
{ {
OnSimpleExpressionGenerator?.Invoke(this, new OnSimpleExpressionGeneratorEventArgs OnSimpleExpressionGenerator?.Invoke(this, new SimpleExpressionGeneratorEventArgs
{ {
SimpleExpression = Children[0].Convert<SimpleExpression>() SimpleExpression = Children[0].Convert<SimpleExpression>()
}); });
} }
else else
{ {
OnRelationGenerator?.Invoke(this, new OnRelationGeneratorEventArgs OnRelationGenerator?.Invoke(this, new RelationGeneratorEventArgs
{ {
Left = Children[0].Convert<SimpleExpression>(), Left = Children[0].Convert<SimpleExpression>(),
Operator = Children[1].Convert<RelationOperator>(), Operator = Children[1].Convert<RelationOperator>(),

View File

@ -1,43 +1,57 @@
using Canon.Core.Abstractions; using Canon.Core.Abstractions;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums; using Canon.Core.Enums;
using Canon.Core.LexicalParser; using Canon.Core.LexicalParser;
using Canon.Core.SemanticParser; using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public class OnNumberGeneratorEventArgs : EventArgs public class NumberGeneratorEventArgs : EventArgs
{ {
public required NumberSemanticToken Token { get; init; } public required NumberSemanticToken Token { get; init; }
} }
public class OnVariableGeneratorEventArgs : EventArgs public class VariableGeneratorEventArgs : EventArgs
{ {
public required Variable Variable { get; init; } public required Variable Variable { get; init; }
} }
public class OnParethnesisGeneratorEventArgs : EventArgs public class ParethnesisGeneratorEventArgs : EventArgs
{ {
public required Expression Expression { get; init; } public required Expression Expression { get; init; }
} }
public class OnProcedureCallGeneratorEventArgs : EventArgs public class NoParameterProcedureCallGeneratorEventArgs : EventArgs
{
public required IdentifierSemanticToken ProcedureName { get; init; }
}
public class ProcedureCallGeneratorEventArgs : EventArgs
{ {
public required IdentifierSemanticToken ProcedureName { get; init; } public required IdentifierSemanticToken ProcedureName { get; init; }
public required ExpressionList Parameters { get; init; } public required ExpressionList Parameters { get; init; }
} }
public class OnNotGeneratorEventArgs : EventArgs public class NotGeneratorEventArgs : EventArgs
{ {
public required Factor Factor { get; init; } public required Factor Factor { get; init; }
} }
public class OnUminusGeneratorEventArgs : EventArgs public class UminusGeneratorEventArgs : EventArgs
{ {
public required Factor Factor { get; init; } public required Factor Factor { get; init; }
} }
public class PlusGeneratorEventArgs : EventArgs
{
public required Factor Factor { get; init; }
}
public class BooleanGeneratorEventArgs : EventArgs
{
public required bool Value { get; init; }
}
public class Factor : NonTerminatedSyntaxNode public class Factor : NonTerminatedSyntaxNode
{ {
public override NonTerminatorType Type => NonTerminatorType.Factor; public override NonTerminatorType Type => NonTerminatorType.Factor;
@ -57,32 +71,47 @@ public class Factor : NonTerminatedSyntaxNode
/// <summary> /// <summary>
/// 使用数值产生式的事件 /// 使用数值产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnNumberGeneratorEventArgs>? OnNumberGenerator; public event EventHandler<NumberGeneratorEventArgs>? OnNumberGenerator;
/// <summary> /// <summary>
/// 使用括号产生式的事件 /// 使用括号产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnParethnesisGeneratorEventArgs>? OnParethnesisGenerator; public event EventHandler<ParethnesisGeneratorEventArgs>? OnParethnesisGenerator;
/// <summary> /// <summary>
/// 使用变量产生式的事件 /// 使用变量产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnVariableGeneratorEventArgs>? OnVariableGenerator; public event EventHandler<VariableGeneratorEventArgs>? OnVariableGenerator;
/// <summary>
/// 使用过程调用产生式的事件
/// </summary>
public event EventHandler<OnProcedureCallGeneratorEventArgs>? OnProcedureCallGenerator;
/// <summary> /// <summary>
/// 使用否定产生式的事件 /// 使用否定产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnNotGeneratorEventArgs>? OnNotGenerator; public event EventHandler<NotGeneratorEventArgs>? OnNotGenerator;
/// <summary> /// <summary>
/// 使用负号产生式的事件 /// 使用负号产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnUminusGeneratorEventArgs>? OnUminusGenerator; public event EventHandler<UminusGeneratorEventArgs>? OnUminusGenerator;
/// <summary>
/// 使用加号产生式的事件
/// </summary>
public event EventHandler<PlusGeneratorEventArgs>? OnPlusGenerator;
/// <summary>
/// 使用布尔值产生式的事件
/// </summary>
public event EventHandler<BooleanGeneratorEventArgs>? OnBooleanGenerator;
/// <summary>
/// 没有参数的过程调用产生式事件
/// </summary>
public event EventHandler<NoParameterProcedureCallGeneratorEventArgs>? OnNoParameterProcedureCallGenerator;
/// <summary>
/// 过程调用产生式的事件
/// </summary>
public event EventHandler<ProcedureCallGeneratorEventArgs>? OnProcedureCallGenerator;
private PascalType? _factorType; private PascalType? _factorType;
@ -97,10 +126,7 @@ public class Factor : NonTerminatedSyntaxNode
return _factorType; return _factorType;
} }
set set { _factorType = value; }
{
_factorType = value;
}
} }
public static Factor Create(List<SyntaxNodeBase> children) public static Factor Create(List<SyntaxNodeBase> children)
@ -112,51 +138,94 @@ public class Factor : NonTerminatedSyntaxNode
{ {
if (Children.Count == 1) if (Children.Count == 1)
{ {
//factor -> num
if (Children[0].IsTerminated) if (Children[0].IsTerminated)
{ {
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token; SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
OnNumberGenerator?.Invoke(this,
new OnNumberGeneratorEventArgs { Token = token.Convert<NumberSemanticToken>() }); switch (token.TokenType)
{
// factor -> num
case SemanticTokenType.Number:
OnNumberGenerator?.Invoke(this,
new NumberGeneratorEventArgs { Token = token.Convert<NumberSemanticToken>() });
break;
// factor -> true | false
case SemanticTokenType.Keyword:
KeywordSemanticToken keywordSemanticToken = token.Convert<KeywordSemanticToken>();
switch (keywordSemanticToken.KeywordType)
{
case KeywordType.True:
OnBooleanGenerator?.Invoke(this, new BooleanGeneratorEventArgs { Value = true });
break;
case KeywordType.False:
OnBooleanGenerator?.Invoke(this, new BooleanGeneratorEventArgs { Value = false });
break;
}
break;
}
} }
// factor -> variable
else else
{ {
OnVariableGenerator?.Invoke(this, OnVariableGenerator?.Invoke(this,
new OnVariableGeneratorEventArgs { Variable = Children[0].Convert<Variable>() }); new VariableGeneratorEventArgs { Variable = Children[0].Convert<Variable>() });
} }
} }
//factor -> ( expression )
else if (Children.Count == 3) else if (Children.Count == 3)
{ {
OnParethnesisGenerator?.Invoke(this, TerminatedSyntaxNode terminatedSyntaxNode = Children[0].Convert<TerminatedSyntaxNode>();
new OnParethnesisGeneratorEventArgs { Expression = Children[1].Convert<Expression>() });
// factor -> ( expression )
if (terminatedSyntaxNode.Token.TokenType == SemanticTokenType.Delimiter)
{
OnParethnesisGenerator?.Invoke(this,
new ParethnesisGeneratorEventArgs { Expression = Children[1].Convert<Expression>() });
}
else
{
// factor -> id ( )
OnNoParameterProcedureCallGenerator?.Invoke(this, new NoParameterProcedureCallGeneratorEventArgs
{
ProcedureName = terminatedSyntaxNode.Token.Convert<IdentifierSemanticToken>()
});
}
} }
//factor -> id ( expression )
else if (Children.Count == 4) else if (Children.Count == 4)
{ {
OnProcedureCallGenerator?.Invoke(this, // factor -> id ( expressionList)
new OnProcedureCallGeneratorEventArgs OnProcedureCallGenerator?.Invoke(this, new ProcedureCallGeneratorEventArgs
{ {
ProcedureName = ProcedureName = Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(), Parameters = Children[2].Convert<ExpressionList>()
Parameters = Children[2].Convert<ExpressionList>() });
});
} }
else else
{ {
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token; SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
Factor factor = Children[1].Convert<Factor>(); Factor factor = Children[1].Convert<Factor>();
if (token.TokenType == SemanticTokenType.Keyword) if (token.TokenType == SemanticTokenType.Keyword)
{ {
// factor -> not factor // factor -> not factor
OnNotGenerator?.Invoke(this, new OnNotGeneratorEventArgs { Factor = factor }); OnNotGenerator?.Invoke(this, new NotGeneratorEventArgs { Factor = factor });
} }
else else
{ {
// factor -> uminus factor OperatorSemanticToken operatorSemanticToken = token.Convert<OperatorSemanticToken>();
OnUminusGenerator?.Invoke(this, new OnUminusGeneratorEventArgs { Factor = factor });
switch (operatorSemanticToken.OperatorType)
{
// factor -> + factor
case OperatorType.Plus:
OnPlusGenerator?.Invoke(this, new PlusGeneratorEventArgs { Factor = factor });
break;
// factor -> - factor
case OperatorType.Minus:
OnUminusGenerator?.Invoke(this, new UminusGeneratorEventArgs { Factor = factor });
break;
}
} }
} }

View File

@ -5,14 +5,14 @@ using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public class OnIdentifierGeneratorEventArgs : EventArgs public class IdentifierGeneratorEventArgs : EventArgs
{ {
public required IdentifierSemanticToken IdentifierToken { get; init; } public required IdentifierSemanticToken IdentifierToken { get; init; }
public required IdentifierList IdentifierList { get; init; } public required IdentifierList IdentifierList { get; init; }
} }
public class OnTypeGeneratorEventArgs : EventArgs public class TypeGeneratorEventArgs : EventArgs
{ {
public required TypeSyntaxNode TypeSyntaxNode { get; init; } public required TypeSyntaxNode TypeSyntaxNode { get; init; }
} }
@ -66,9 +66,9 @@ public class IdentifierList : NonTerminatedSyntaxNode
/// </summary> /// </summary>
public bool IsProcedure { get; set; } public bool IsProcedure { get; set; }
public event EventHandler<OnIdentifierGeneratorEventArgs>? OnIdentifierGenerator; public event EventHandler<IdentifierGeneratorEventArgs>? OnIdentifierGenerator;
public event EventHandler<OnTypeGeneratorEventArgs>? OnTypeGenerator; public event EventHandler<TypeGeneratorEventArgs>? OnTypeGenerator;
public static IdentifierList Create(List<SyntaxNodeBase> children) public static IdentifierList Create(List<SyntaxNodeBase> children)
{ {
@ -80,11 +80,11 @@ public class IdentifierList : NonTerminatedSyntaxNode
if (Children.Count == 2) if (Children.Count == 2)
{ {
OnTypeGenerator?.Invoke(this, OnTypeGenerator?.Invoke(this,
new OnTypeGeneratorEventArgs { TypeSyntaxNode = Children[1].Convert<TypeSyntaxNode>() }); new TypeGeneratorEventArgs { TypeSyntaxNode = Children[1].Convert<TypeSyntaxNode>() });
} }
else else
{ {
OnIdentifierGenerator?.Invoke(this, new OnIdentifierGeneratorEventArgs OnIdentifierGenerator?.Invoke(this, new IdentifierGeneratorEventArgs
{ {
IdentifierToken = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(), IdentifierToken = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
IdentifierList = Children[2].Convert<IdentifierList>() IdentifierList = Children[2].Convert<IdentifierList>()

View File

@ -4,7 +4,7 @@ using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public class OnIndexGeneratorEventArgs : EventArgs public class IndexGeneratorEventArgs : EventArgs
{ {
public required ExpressionList IndexParameters { get; init; } public required ExpressionList IndexParameters { get; init; }
} }
@ -38,7 +38,7 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
/// <summary> /// <summary>
/// 使用了索引产生式的事件 /// 使用了索引产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnIndexGeneratorEventArgs>? OnIndexGenerator; public event EventHandler<IndexGeneratorEventArgs>? OnIndexGenerator;
public static IdentifierVarPart Create(List<SyntaxNodeBase> children) public static IdentifierVarPart Create(List<SyntaxNodeBase> children)
{ {
@ -49,7 +49,7 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
{ {
if (Children.Count == 3) if (Children.Count == 3)
{ {
OnIndexGenerator?.Invoke(this, new OnIndexGeneratorEventArgs() OnIndexGenerator?.Invoke(this, new IndexGeneratorEventArgs()
{ {
IndexParameters = Children[1].Convert<ExpressionList>() IndexParameters = Children[1].Convert<ExpressionList>()
}); });

View File

@ -1,14 +1,17 @@
using Canon.Core.Abstractions; using Canon.Core.Abstractions;
using Canon.Core.Enums; using Canon.Core.Enums;
using Canon.Core.LexicalParser; using Canon.Core.LexicalParser;
using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public class OnParameterGeneratorEventArgs : EventArgs public class ParameterGeneratorEventArgs : EventArgs
{ {
public required ExpressionList Parameters { get; init; } public required ExpressionList Parameters { get; init; }
} }
public class NoParameterGeneratorEventArgs : EventArgs;
public class ProcedureCall : NonTerminatedSyntaxNode public class ProcedureCall : NonTerminatedSyntaxNode
{ {
public override NonTerminatorType Type => NonTerminatorType.ProcedureCall; public override NonTerminatorType Type => NonTerminatorType.ProcedureCall;
@ -19,7 +22,31 @@ public class ProcedureCall : NonTerminatedSyntaxNode
/// <summary> /// <summary>
/// 调用函数时含有参数的事件 /// 调用函数时含有参数的事件
/// </summary> /// </summary>
public event EventHandler<OnParameterGeneratorEventArgs>? OnParameterGenerator; public event EventHandler<ParameterGeneratorEventArgs>? OnParameterGenerator;
/// <summary>
/// 调用函数是没有参数的事件
/// </summary>
public event EventHandler<NoParameterGeneratorEventArgs>? OnNoParameterGenerator;
private PascalType? _pascalType;
public PascalType ReturnType
{
get
{
if (_pascalType is null)
{
throw new InvalidOperationException();
}
return _pascalType;
}
set
{
_pascalType = value;
}
}
public override void PreVisit(SyntaxNodeVisitor visitor) public override void PreVisit(SyntaxNodeVisitor visitor)
{ {
@ -42,12 +69,17 @@ public class ProcedureCall : NonTerminatedSyntaxNode
{ {
if (Children.Count == 4) if (Children.Count == 4)
{ {
OnParameterGenerator?.Invoke(this, new OnParameterGeneratorEventArgs OnParameterGenerator?.Invoke(this, new ParameterGeneratorEventArgs
{ {
Parameters = Children[2].Convert<ExpressionList>() Parameters = Children[2].Convert<ExpressionList>()
}); });
} }
else
{
OnNoParameterGenerator?.Invoke(this, new NoParameterGeneratorEventArgs());
}
OnParameterGenerator = null; OnParameterGenerator = null;
OnNoParameterGenerator = null;
} }
} }

View File

@ -5,12 +5,12 @@ using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public class OnTermGeneratorEventArgs : EventArgs public class TermGeneratorEventArgs : EventArgs
{ {
public required Term Term { get; init; } public required Term Term { get; init; }
} }
public class OnAddGeneratorEventArgs : EventArgs public class AddGeneratorEventArgs : EventArgs
{ {
public required SimpleExpression Left { get; init; } public required SimpleExpression Left { get; init; }
@ -38,12 +38,12 @@ public class SimpleExpression : NonTerminatedSyntaxNode
/// <summary> /// <summary>
/// 直接赋值产生式的事件 /// 直接赋值产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnTermGeneratorEventArgs>? OnTermGenerator; public event EventHandler<TermGeneratorEventArgs>? OnTermGenerator;
/// <summary> /// <summary>
/// 加法产生式的事件 /// 加法产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnAddGeneratorEventArgs>? OnAddGenerator; public event EventHandler<AddGeneratorEventArgs>? OnAddGenerator;
private PascalType? _simpleExpressionType; private PascalType? _simpleExpressionType;
@ -73,14 +73,14 @@ public class SimpleExpression : NonTerminatedSyntaxNode
{ {
if (Children.Count == 1) if (Children.Count == 1)
{ {
OnTermGenerator?.Invoke(this, new OnTermGeneratorEventArgs OnTermGenerator?.Invoke(this, new TermGeneratorEventArgs
{ {
Term = Children[0].Convert<Term>() Term = Children[0].Convert<Term>()
}); });
} }
else else
{ {
OnAddGenerator?.Invoke(this, new OnAddGeneratorEventArgs OnAddGenerator?.Invoke(this, new AddGeneratorEventArgs
{ {
Left = Children[0].Convert<SimpleExpression>(), Left = Children[0].Convert<SimpleExpression>(),
Operator = Children[1].Convert<AddOperator>(), Operator = Children[1].Convert<AddOperator>(),

View File

@ -5,21 +5,14 @@ using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public class OnAssignGeneratorEventArgs : EventArgs public class AssignGeneratorEventArgs : EventArgs
{ {
public required Variable Variable { get; init; } public required Variable Variable { get; init; }
public required Expression Expression { get; init; } public required Expression Expression { get; init; }
} }
public class OnReturnGeneratorEventArgs : EventArgs public class IfGeneratorEventArgs : EventArgs
{
public required IdentifierSemanticToken FunctionName { get; set; }
public required Expression Expression { get; init; }
}
public class OnIfGeneratorEventArgs : EventArgs
{ {
public required Expression Condition { get; init; } public required Expression Condition { get; init; }
@ -28,7 +21,7 @@ public class OnIfGeneratorEventArgs : EventArgs
public required ElsePart ElseSentence { get; init; } public required ElsePart ElseSentence { get; init; }
} }
public class OnForGeneratorEventArgs : EventArgs public class ForGeneratorEventArgs : EventArgs
{ {
public required IdentifierSemanticToken Iterator { get; init; } public required IdentifierSemanticToken Iterator { get; init; }
@ -58,22 +51,17 @@ public class Statement : NonTerminatedSyntaxNode
/// <summary> /// <summary>
/// 使用赋值产生式的事件 /// 使用赋值产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnAssignGeneratorEventArgs>? OnAssignGenerator; public event EventHandler<AssignGeneratorEventArgs>? OnAssignGenerator;
/// <summary>
/// 使用返回产生式的事件
/// </summary>
public event EventHandler<OnReturnGeneratorEventArgs>? OnReturnGenerator;
/// <summary> /// <summary>
/// 使用If产生式的事件 /// 使用If产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnIfGeneratorEventArgs>? OnIfGenerator; public event EventHandler<IfGeneratorEventArgs>? OnIfGenerator;
/// <summary> /// <summary>
/// 使用For产生式的事件 /// 使用For产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnForGeneratorEventArgs>? OnForGenerator; public event EventHandler<ForGeneratorEventArgs>? OnForGenerator;
public static Statement Create(List<SyntaxNodeBase> children) public static Statement Create(List<SyntaxNodeBase> children)
{ {
@ -84,41 +72,32 @@ public class Statement : NonTerminatedSyntaxNode
{ {
if (Children.Count == 3) if (Children.Count == 3)
{ {
if (Children[0].IsTerminated) OnAssignGenerator?.Invoke(this,
{ new AssignGeneratorEventArgs
OnReturnGenerator?.Invoke(this, new OnReturnGeneratorEventArgs
{ {
FunctionName = Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(), Variable = Children[0].Convert<Variable>(), Expression = Children[2].Convert<Expression>()
Expression = Children[2].Convert<Expression>()
}); });
}
else
{
OnAssignGenerator?.Invoke(this, new OnAssignGeneratorEventArgs
{
Variable = Children[0].Convert<Variable>(),
Expression = Children[2].Convert<Expression>()
});
}
} }
else if (Children.Count == 5) else if (Children.Count == 5)
{ {
OnIfGenerator?.Invoke(this, new OnIfGeneratorEventArgs OnIfGenerator?.Invoke(this,
{ new IfGeneratorEventArgs
Condition = Children[1].Convert<Expression>(), {
Sentence = Children[3].Convert<Statement>(), Condition = Children[1].Convert<Expression>(),
ElseSentence = Children[4].Convert<ElsePart>() Sentence = Children[3].Convert<Statement>(),
}); ElseSentence = Children[4].Convert<ElsePart>()
});
} }
else if (Children.Count == 8) else if (Children.Count == 8)
{ {
OnForGenerator?.Invoke(this, new OnForGeneratorEventArgs OnForGenerator?.Invoke(this,
{ new ForGeneratorEventArgs
Iterator = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(), {
Begin = Children[3].Convert<Expression>(), Iterator = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
End = Children[5].Convert<Expression>(), Begin = Children[3].Convert<Expression>(),
Sentence = Children[7].Convert<Statement>() End = Children[5].Convert<Expression>(),
}); Sentence = Children[7].Convert<Statement>()
});
} }
} }
} }

View File

@ -4,9 +4,9 @@ using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public class OnProcedureGeneratorEventArgs : EventArgs; public class ProcedureGeneratorEventArgs : EventArgs;
public class OnFunctionGeneratorEventArgs : EventArgs public class FunctionGeneratorEventArgs : EventArgs
{ {
public required BasicType ReturnType { get; init; } public required BasicType ReturnType { get; init; }
} }
@ -40,9 +40,9 @@ public class SubprogramHead : NonTerminatedSyntaxNode
RaiseEvent(); RaiseEvent();
} }
public event EventHandler<OnProcedureGeneratorEventArgs>? OnProcedureGenerator; public event EventHandler<ProcedureGeneratorEventArgs>? OnProcedureGenerator;
public event EventHandler<OnFunctionGeneratorEventArgs>? OnFunctionGenerator; public event EventHandler<FunctionGeneratorEventArgs>? OnFunctionGenerator;
public static SubprogramHead Create(List<SyntaxNodeBase> children) public static SubprogramHead Create(List<SyntaxNodeBase> children)
{ {
@ -71,12 +71,12 @@ public class SubprogramHead : NonTerminatedSyntaxNode
{ {
if (IsProcedure) if (IsProcedure)
{ {
OnProcedureGenerator?.Invoke(this, new OnProcedureGeneratorEventArgs()); OnProcedureGenerator?.Invoke(this, new ProcedureGeneratorEventArgs());
} }
else else
{ {
OnFunctionGenerator?.Invoke(this, OnFunctionGenerator?.Invoke(this,
new OnFunctionGeneratorEventArgs { ReturnType = Children[4].Convert<BasicType>() }); new FunctionGeneratorEventArgs { ReturnType = Children[4].Convert<BasicType>() });
} }
OnProcedureGenerator = null; OnProcedureGenerator = null;

View File

@ -5,7 +5,7 @@ using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public abstract class SyntaxNodeBase : ICCodeGenerator public abstract class SyntaxNodeBase
{ {
public abstract bool IsTerminated { get; } public abstract bool IsTerminated { get; }
@ -25,13 +25,6 @@ public abstract class SyntaxNodeBase : ICCodeGenerator
return result; return result;
} }
/// <summary>
/// 语法树节点基类对于生成C代码的默认实现
/// </summary>
public virtual void GenerateCCode(CCodeBuilder builder)
{
}
public override string ToString() public override string ToString()
{ {
return IsTerminated.ToString(); return IsTerminated.ToString();

View File

@ -5,12 +5,12 @@ using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public class OnFactorGeneratorEventArgs : EventArgs public class FactorGeneratorEventArgs : EventArgs
{ {
public required Factor Factor { get; init; } public required Factor Factor { get; init; }
} }
public class OnMultiplyGeneratorEventArgs : EventArgs public class MultiplyGeneratorEventArgs : EventArgs
{ {
public required Term Left { get; init; } public required Term Left { get; init; }
@ -38,12 +38,12 @@ public class Term : NonTerminatedSyntaxNode
/// <summary> /// <summary>
/// 直接赋值产生式的事件 /// 直接赋值产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnFactorGeneratorEventArgs>? OnFactorGenerator; public event EventHandler<FactorGeneratorEventArgs>? OnFactorGenerator;
/// <summary> /// <summary>
/// 乘法产生式的事件 /// 乘法产生式的事件
/// </summary> /// </summary>
public event EventHandler<OnMultiplyGeneratorEventArgs>? OnMultiplyGenerator; public event EventHandler<MultiplyGeneratorEventArgs>? OnMultiplyGenerator;
private PascalType? _termType; private PascalType? _termType;
@ -73,14 +73,14 @@ public class Term : NonTerminatedSyntaxNode
{ {
if (Children.Count == 1) if (Children.Count == 1)
{ {
OnFactorGenerator?.Invoke(this, new OnFactorGeneratorEventArgs OnFactorGenerator?.Invoke(this, new FactorGeneratorEventArgs
{ {
Factor = Children[0].Convert<Factor>() Factor = Children[0].Convert<Factor>()
}); });
} }
else else
{ {
OnMultiplyGenerator?.Invoke(this, new OnMultiplyGeneratorEventArgs OnMultiplyGenerator?.Invoke(this, new MultiplyGeneratorEventArgs
{ {
Left = Children[0].Convert<Term>(), Left = Children[0].Convert<Term>(),
Operator = Children[1].Convert<MultiplyOperator>(), Operator = Children[1].Convert<MultiplyOperator>(),

View File

@ -5,12 +5,12 @@ using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes; namespace Canon.Core.SyntaxNodes;
public class OnBasicTypeGeneratorEventArgs : EventArgs public class BasicTypeGeneratorEventArgs : EventArgs
{ {
public required BasicType BasicType { get; init; } public required BasicType BasicType { get; init; }
} }
public class OnArrayTypeGeneratorEventArgs : EventArgs public class ArrayTypeGeneratorEventArgs : EventArgs
{ {
public required Period Period { get; init; } public required Period Period { get; init; }
@ -33,9 +33,9 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
RaiseEvent(); RaiseEvent();
} }
public event EventHandler<OnBasicTypeGeneratorEventArgs>? OnBasicTypeGenerator; public event EventHandler<BasicTypeGeneratorEventArgs>? OnBasicTypeGenerator;
public event EventHandler<OnArrayTypeGeneratorEventArgs>? OnArrayTypeGenerator; public event EventHandler<ArrayTypeGeneratorEventArgs>? OnArrayTypeGenerator;
/// <summary> /// <summary>
/// 是否在过程定义中使用 /// 是否在过程定义中使用
@ -74,14 +74,14 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
{ {
if (Children.Count == 1) if (Children.Count == 1)
{ {
OnBasicTypeGenerator?.Invoke(this, new OnBasicTypeGeneratorEventArgs OnBasicTypeGenerator?.Invoke(this, new BasicTypeGeneratorEventArgs
{ {
BasicType = Children[0].Convert<BasicType>() BasicType = Children[0].Convert<BasicType>()
}); });
} }
else else
{ {
OnArrayTypeGenerator?.Invoke(this, new OnArrayTypeGeneratorEventArgs OnArrayTypeGenerator?.Invoke(this, new ArrayTypeGeneratorEventArgs
{ {
Period = Children[2].Convert<Period>(), Period = Children[2].Convert<Period>(),
BasicType = Children[5].Convert<BasicType>() BasicType = Children[5].Convert<BasicType>()

View File

@ -30,6 +30,7 @@ public class BasicTest
string result = visitor.Builder.Build(); string result = visitor.Builder.Build();
_output.WriteLine(result); _output.WriteLine(result);
Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nint main()\n{\n;\n\nreturn 0;\n}\n", visitor.Builder.Build()); Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nint main()\n{\n;\n\nreturn 0;\n}\n",
visitor.Builder.Build());
} }
} }

View File

@ -72,13 +72,37 @@ public class SubprogramTests
string result = visitor.Builder.Build(); string result = visitor.Builder.Build();
_output.WriteLine(result); _output.WriteLine(result);
Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nbool b, a;" + Assert.Equal("""
"\nint func1(int* a, int b, double c)\n{\nint func1;\n" + #include <stdbool.h>
"{\n(*a) = b + c;\nfunc1 = (*a) * 3;\n;\n}\nreturn func1;\n}\n" + #include <stdio.h>
"char func2(bool* a, bool* b, char c[][6])\n{\nchar func2;\n" + bool b, a;
"{\n(*a) = (*b) && (!(*b));\nfunc2 = c[5-0][8-3];\n;\n}\nreturn func2;\n}" + int func1(int* a, int b, double c)
"\nint main()\n{\n;\n\nreturn 0;\n}\n", visitor.Builder.Build()); {
int func1;
{
(*a) = b + c;
func1 = (*a) * 3;
;
}
return func1;
}
char func2(bool* a, bool* b, char c[][6])
{
char func2;
{
(*a) = (*b) && (~(*b));
func2 = c[5-0][8-3];
;
}
return func2;
}
int main()
{
;
return 0;
}
""", visitor.Builder.Build());
} }
} }

View File

@ -9,10 +9,10 @@ public class PascalGrammarTests
public void DoNothingTest() public void DoNothingTest()
{ {
const string program = """ const string program = """
program DoNothing; program DoNothing;
begin begin
end. end.
"""; """;
ProgramStruct root = CompilerHelpers.Analyse(program); ProgramStruct root = CompilerHelpers.Analyse(program);
Assert.Equal("DoNothing", root.Head.ProgramName.LiteralValue); Assert.Equal("DoNothing", root.Head.ProgramName.LiteralValue);
@ -161,4 +161,86 @@ public class PascalGrammarTests
CompilerHelpers.Analyse(program); CompilerHelpers.Analyse(program);
} }
[Fact]
public void ProcedureCallTest()
{
const string program = """
program main;
var a : integer;
function test : integer;
begin
end;
begin
test;
a := test;
test();
a := test();
end.
""";
CompilerHelpers.Analyse(program);
}
[Fact]
public void ProcedureDefinitionTest()
{
const string program = """
program main;
procedure test();
begin
end;
begin
test();
end.
""";
CompilerHelpers.Analyse(program);
}
[Fact]
public void FactorTest()
{
const string program = """
program main;
var a : integer;
begin
a := 1 + +1;
a := 1 - -1;
a := 1 + -1;
a := 1 - +1;
end.
""";
CompilerHelpers.Analyse(program);
}
[Fact]
public void TrueFalseTest()
{
const string program = """
program main;
const a = true; b = false;
var c, d : boolean;
begin
c := true;
d := false;
end.
""";
CompilerHelpers.Analyse(program);
}
[Fact]
public void ProcedureAndVariableTest()
{
const string program = """
program main;
begin
test
end.
""";
CompilerHelpers.Analyse(program);
}
} }

View File

@ -1,5 +1,5 @@
using Canon.Core.Abstractions; using Canon.Core.Enums;
using Canon.Core.Enums; using Canon.Core.Exceptions;
using Canon.Core.GrammarParser; using Canon.Core.GrammarParser;
using Xunit.Abstractions; using Xunit.Abstractions;
@ -159,11 +159,6 @@ public class SimpleGrammarWithEmptyTests(ITestOutputHelper testOutputHelper)
}; };
Grammar grammar = builder.Build(); Grammar grammar = builder.Build();
IGrammarParser parser = grammar.ToGrammarParser(); Assert.Throws<ReduceAndShiftConflictException>(() => grammar.ToGrammarParser());
ITransformer transformer1 = parser.BeginTransformer;
Assert.Equal(3, transformer1.ShiftTable.Count);
Assert.Single(transformer1.ReduceTable);
Assert.Contains(new NonTerminator(NonTerminatorType.ProgramStruct),transformer1.ShiftTable);
} }
} }

View File

@ -26,6 +26,8 @@ public class KeywordTypeTests
[InlineData("to", KeywordType.To)] [InlineData("to", KeywordType.To)]
[InlineData("do", KeywordType.Do)] [InlineData("do", KeywordType.Do)]
[InlineData("DO", KeywordType.Do)] [InlineData("DO", KeywordType.Do)]
[InlineData("true", KeywordType.True)]
[InlineData("false", KeywordType.False)]
public void SmokeTest(string input, KeywordType type) public void SmokeTest(string input, KeywordType type)
{ {
IEnumerable<SemanticToken> tokensEnumerable = _lexer.Tokenize(new StringSourceReader(input)); IEnumerable<SemanticToken> tokensEnumerable = _lexer.Tokenize(new StringSourceReader(input));

View File

@ -7,7 +7,7 @@ namespace Canon.Tests.SemanticTests;
public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper) public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
{ {
private readonly TestLogger<TypeCheckVisitor> _logger = new(testOutputHelper); private readonly TestLogger _logger = new(testOutputHelper);
[Fact] [Fact]
public void ConstTypeTest() public void ConstTypeTest()
@ -549,6 +549,92 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
Assert.True(visitor.IsError); Assert.True(visitor.IsError);
} }
[Fact]
public void TrueFalseTest()
{
const string program = """
program main;
var a : boolean;
begin
a := true;
a := false;
end.
""";
TypeCheckVisitor visitor = CheckType(program);
Assert.False(visitor.IsError);
}
[Fact]
public void NotTest()
{
const string program = """
program main;
var a: integer;
begin
a := 60;
write(not a);
end.
""";
TypeCheckVisitor visitor = CheckType(program);
Assert.False(visitor.IsError);
}
[Fact]
public void PascalFunctionTest()
{
const string program = """
program main;
var a : integer;
begin
write(a);
read(a);
writeln(a);
end.
""";
TypeCheckVisitor visitor = CheckType(program);
Assert.False(visitor.IsError);
}
[Fact]
public void FunctionCalculateTest()
{
const string program = """
program main;
var a : integer;
function test : integer;
begin
test := 1;
end;
begin
a := a + test;
end.
""";
TypeCheckVisitor visitor = CheckType(program);
Assert.False(visitor.IsError);
}
[Fact]
public void FunctionParameterCalculationTest()
{
const string program = """
program main;
var a : integer;
function test (p : integer) : integer;
begin
test := p;
end;
begin
a := 1 + test(1);
end.
""";
TypeCheckVisitor visitor = CheckType(program);
Assert.False(visitor.IsError);
}
private TypeCheckVisitor CheckType(string program) private TypeCheckVisitor CheckType(string program)
{ {
ProgramStruct root = CompilerHelpers.Analyse(program); ProgramStruct root = CompilerHelpers.Analyse(program);

View File

@ -1,24 +1,16 @@
using Microsoft.Extensions.Logging; using Canon.Core.Abstractions;
using Microsoft.Extensions.Logging;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace Canon.Tests.Utils; namespace Canon.Tests.Utils;
public class TestLogger<T>(ITestOutputHelper testOutputHelper) : ILogger<T>, IDisposable public class TestLogger(ITestOutputHelper testOutputHelper) : ICompilerLogger
{ {
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
Func<TState, Exception?, string> formatter) Func<TState, Exception?, string> formatter)
{ {
testOutputHelper.WriteLine("{0}: {1}", logLevel, formatter(state, exception)); testOutputHelper.WriteLine($"{logLevel}: {formatter(state, exception)}");
} }
public bool IsEnabled(LogLevel logLevel) => false; public string Build() => string.Empty;
public void Dispose()
{
}
public IDisposable BeginScope<TState>(TState state) where TState : notnull
{
return this;
}
} }

View File

@ -33,7 +33,7 @@ def compile_files():
print("Info: compile ", file) print("Info: compile ", file)
if not (Path("open_set") / file.stem).exists(): if not (Path("open_set") / file.stem).exists():
os.system("fpc " + str(file)) os.system("fpc " + str(file))
os.system("./pacss -i " + str(file)) os.system("./pascc -i " + str(file))
c_file = "./open_set/" + file.stem + ".c" c_file = "./open_set/" + file.stem + ".c"
c_binary = "open_set/" + file.stem + ".out" c_binary = "open_set/" + file.stem + ".out"
os.system("gcc " + c_file + " -o " + c_binary) os.system("gcc " + c_file + " -o " + c_binary)