feat: 按照open_set中的示例调整语法 (#71)
添加了构建LR分析表冲突的报错 Reviewed-on: PostGuard/Canon#71
This commit is contained in:
parent
feddbff205
commit
6130adfa7c
|
@ -1,8 +1,5 @@
|
|||
name: Integration Test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
Open-Set-Test:
|
||||
|
@ -18,8 +15,10 @@ jobs:
|
|||
save-always: true
|
||||
- name: Build binary file
|
||||
run: |
|
||||
cd ./Canon.Console
|
||||
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
|
||||
run: |
|
||||
python scripts/integration_test.py run
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -485,3 +485,6 @@ $RECYCLE.BIN/
|
|||
|
||||
# Database Source File
|
||||
*.db
|
||||
|
||||
# Pascall C Compiler
|
||||
pascc
|
||||
|
|
|
@ -62,7 +62,9 @@ public enum KeywordType
|
|||
Not,
|
||||
Mod,
|
||||
And,
|
||||
Or
|
||||
Or,
|
||||
True,
|
||||
False
|
||||
}
|
||||
|
||||
public enum OperatorType
|
||||
|
@ -99,11 +101,3 @@ public enum StateType
|
|||
Unknown,
|
||||
Done
|
||||
}
|
||||
|
||||
public enum BasicIdType
|
||||
{
|
||||
Int,
|
||||
Real,
|
||||
Char,
|
||||
Bool
|
||||
}
|
||||
|
|
6
Canon.Core/Exceptions/ReduceAndShiftConflictException.cs
Normal file
6
Canon.Core/Exceptions/ReduceAndShiftConflictException.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
namespace Canon.Core.Exceptions;
|
||||
|
||||
public class ReduceAndShiftConflictException : Exception
|
||||
{
|
||||
|
||||
}
|
17
Canon.Core/Exceptions/ReduceConflictException.cs
Normal file
17
Canon.Core/Exceptions/ReduceConflictException.cs
Normal 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
|
@ -1,4 +1,6 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.Exceptions;
|
||||
|
||||
namespace Canon.Core.GrammarParser;
|
||||
|
||||
|
@ -45,8 +47,18 @@ public class Grammar
|
|||
{
|
||||
if (expression.Pos == expression.Right.Count)
|
||||
{
|
||||
transformer.ReduceTable.TryAdd(expression.LookAhead, new ReduceInformation(
|
||||
expression.Right.Count, expression.Left));
|
||||
if (transformer.ShiftTable.ContainsKey(expression.LookAhead))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +76,19 @@ public class Grammar
|
|||
transformers.Add(pair.Value, 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 Terminator(OperatorType.Plus), Terminator.NumberTerminator
|
||||
|
@ -114,6 +114,12 @@ public static class PascalGrammar
|
|||
],
|
||||
[
|
||||
Terminator.CharacterTerminator,
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.True)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.False)
|
||||
]
|
||||
]
|
||||
},
|
||||
|
@ -245,6 +251,10 @@ public static class PascalGrammar
|
|||
[
|
||||
Terminator.EmptyTerminator,
|
||||
],
|
||||
[
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
new Terminator(DelimiterType.RightParenthesis)
|
||||
],
|
||||
[
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
new NonTerminator(NonTerminatorType.ParameterList),
|
||||
|
@ -334,13 +344,10 @@ public static class PascalGrammar
|
|||
{
|
||||
// Statement -> ε
|
||||
// | Variable AssignOp Expression
|
||||
// | FuncId AssignOp Expression
|
||||
// | ProcedureCall
|
||||
// | CompoundStatement
|
||||
// | if Expression then Statement ElsePart
|
||||
// | for id AssignOp Expression to Expression do Statement
|
||||
// | read ( VariableList )
|
||||
// | write( ExpressionList )
|
||||
// 注意这里 read 和 write 作为普通的函数调用处理了
|
||||
// 因此下面并没有单独声明
|
||||
new NonTerminator(NonTerminatorType.Statement), [
|
||||
|
@ -354,12 +361,6 @@ public static class PascalGrammar
|
|||
new Terminator(OperatorType.Assign),
|
||||
new NonTerminator(NonTerminatorType.Expression)
|
||||
],
|
||||
[
|
||||
// FuncId AssignOp Expression
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(OperatorType.Assign),
|
||||
new NonTerminator(NonTerminatorType.Expression)
|
||||
],
|
||||
[
|
||||
// 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), [
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
],
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
new Terminator(DelimiterType.RightParenthesis)
|
||||
],
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
|
@ -506,9 +512,13 @@ public static class PascalGrammar
|
|||
{
|
||||
// Factor -> num | Variable
|
||||
// | ( Expression )
|
||||
// | id ()
|
||||
// | id (ExpressionList)
|
||||
// | not Factor
|
||||
// | minus Factor
|
||||
// | - Factor
|
||||
// | + Factor
|
||||
// | true
|
||||
// | false
|
||||
new NonTerminator(NonTerminatorType.Factor), [
|
||||
[
|
||||
Terminator.NumberTerminator,
|
||||
|
@ -521,6 +531,11 @@ public static class PascalGrammar
|
|||
new NonTerminator(NonTerminatorType.Expression),
|
||||
new Terminator(DelimiterType.RightParenthesis)
|
||||
],
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
new Terminator(DelimiterType.RightParenthesis)
|
||||
],
|
||||
[
|
||||
Terminator.IdentifierTerminator,
|
||||
new Terminator(DelimiterType.LeftParenthesis),
|
||||
|
@ -534,6 +549,16 @@ public static class PascalGrammar
|
|||
[
|
||||
new Terminator(OperatorType.Minus),
|
||||
new NonTerminator(NonTerminatorType.Factor)
|
||||
],
|
||||
[
|
||||
new Terminator(OperatorType.Plus),
|
||||
new NonTerminator(NonTerminatorType.Factor)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.True)
|
||||
],
|
||||
[
|
||||
new Terminator(KeywordType.False)
|
||||
]
|
||||
]
|
||||
},
|
||||
|
|
|
@ -31,7 +31,9 @@ public static class LexRules
|
|||
{ "not", KeywordType.Not },
|
||||
{ "mod", KeywordType.Mod },
|
||||
{ "and", KeywordType.And },
|
||||
{ "or", KeywordType.Or }
|
||||
{ "or", KeywordType.Or },
|
||||
{ "true", KeywordType.True },
|
||||
{ "false", KeywordType.False }
|
||||
};
|
||||
|
||||
public static bool GetKeywordTypeByKeywprd(string keyword, out KeywordType type)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Globalization;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
@ -7,7 +8,7 @@ using BasicType = Canon.Core.SyntaxNodes.BasicType;
|
|||
|
||||
namespace Canon.Core.SemanticParser;
|
||||
|
||||
public class CCodeGenerateVisitor : TypeCheckVisitor
|
||||
public class CCodeGenerateVisitor(ICompilerLogger? logger = null) : TypeCheckVisitor(logger)
|
||||
{
|
||||
public CCodeBuilder Builder { get; } = new();
|
||||
|
||||
|
@ -142,7 +143,7 @@ public class CCodeGenerateVisitor : TypeCheckVisitor
|
|||
Builder.AddString("(");
|
||||
List<string> parametersInfo = new();
|
||||
|
||||
foreach (List<Symbol> children in _valueParameters)
|
||||
foreach (List<Symbol> children in ValueParameters)
|
||||
{
|
||||
foreach (Symbol symbol in children.AsEnumerable().Reverse())
|
||||
{
|
||||
|
@ -432,10 +433,6 @@ public class CCodeGenerateVisitor : TypeCheckVisitor
|
|||
token.ParseAsReal().ToString(CultureInfo.InvariantCulture);
|
||||
Builder.AddString(num);
|
||||
};
|
||||
factor.OnProcedureCallGenerator += (_, _) =>
|
||||
{
|
||||
Builder.AddString(")");
|
||||
};
|
||||
factor.OnNotGenerator += (_, _) =>
|
||||
{
|
||||
Builder.AddString(")");
|
||||
|
@ -449,25 +446,10 @@ public class CCodeGenerateVisitor : TypeCheckVisitor
|
|||
public override void PreVisit(Factor 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 += (_, _) =>
|
||||
{
|
||||
Builder.AddString("(!");
|
||||
Builder.AddString("(~");
|
||||
};
|
||||
factor.OnUminusGenerator += (_, _) =>
|
||||
{
|
||||
|
|
|
@ -8,6 +8,11 @@ public class PascalFunctionType(List<PascalParameterType> parameters, PascalType
|
|||
|
||||
public PascalType ReturnType { get; } = returnType;
|
||||
|
||||
/// <summary>
|
||||
/// Pascal核心库函数的类型
|
||||
/// </summary>
|
||||
public static PascalFunctionType CoreFuntionType => new PascalFunctionType([], PascalBasicType.Void);
|
||||
|
||||
public override string TypeName
|
||||
{
|
||||
get
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
|
@ -7,8 +8,11 @@ using Expression = Canon.Core.SyntaxNodes.Expression;
|
|||
|
||||
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();
|
||||
|
||||
/// <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.OnVariableGenerator += (_, e) => { factor.FactorType = e.Variable.VariableType; };
|
||||
|
||||
// factor -> (expression)
|
||||
factor.OnParethnesisGenerator += (_, e) => { factor.FactorType = e.Expression.ExpressionType; };
|
||||
|
||||
// factor -> id (expression_list)
|
||||
// factor -> id ()
|
||||
factor.OnNoParameterProcedureCallGenerator += (_, e) =>
|
||||
{
|
||||
if (ValidateProcedureCall(e.ProcedureName, [], out PascalFunctionType? functionType))
|
||||
{
|
||||
if (functionType.ReturnType != PascalBasicType.Void)
|
||||
{
|
||||
factor.FactorType = functionType.ReturnType;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsError = true;
|
||||
logger?.LogError("The procedure '{}' returns void.", e.ProcedureName.IdentifierName);
|
||||
}
|
||||
}
|
||||
|
||||
factor.FactorType = PascalBasicType.Void;
|
||||
};
|
||||
|
||||
// factor -> id ( ExpressionList)
|
||||
factor.OnProcedureCallGenerator += (_, e) =>
|
||||
{
|
||||
if (!SymbolTable.TryGetSymbol(e.ProcedureName.IdentifierName, out Symbol? procedure))
|
||||
if (ValidateProcedureCall(e.ProcedureName, e.Parameters.Expressions, out PascalFunctionType? functionType))
|
||||
{
|
||||
IsError = true;
|
||||
logger?.LogError("Procedure '{}' does not define.", e.ProcedureName.IdentifierName);
|
||||
return;
|
||||
}
|
||||
|
||||
PascalFunctionType? functionType = procedure.SymbolType as PascalFunctionType;
|
||||
if (functionType is null)
|
||||
if (functionType.ReturnType != PascalBasicType.Void)
|
||||
{
|
||||
if (SymbolTable.TryGetParent(out SymbolTable? parent))
|
||||
{
|
||||
if (parent.TryGetSymbol(e.ProcedureName.IdentifierName, out procedure))
|
||||
{
|
||||
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)
|
||||
else
|
||||
{
|
||||
IsError = true;
|
||||
logger?.LogError("Parameter expect '{}' but '{}'",
|
||||
parameterType.ParameterType.TypeName, expression.ExpressionType);
|
||||
return;
|
||||
logger?.LogError("The procedure '{}' returns void.", e.ProcedureName.IdentifierName);
|
||||
}
|
||||
}
|
||||
|
||||
factor.FactorType = PascalBasicType.Void;
|
||||
};
|
||||
|
||||
// factor -> factor
|
||||
factor.OnNotGenerator += (_, e) =>
|
||||
{
|
||||
if (e.Factor.FactorType != PascalBasicType.Boolean)
|
||||
{
|
||||
IsError = true;
|
||||
logger?.LogError("The boolean type is expected.");
|
||||
return;
|
||||
}
|
||||
|
||||
factor.FactorType = PascalBasicType.Boolean;
|
||||
};
|
||||
// factor -> not factor
|
||||
factor.OnNotGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; };
|
||||
|
||||
// factor -> uminus factor
|
||||
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)
|
||||
|
@ -308,7 +287,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
|||
/// <summary>
|
||||
/// 多个ValueParameter下定义的参数列表
|
||||
/// </summary>
|
||||
protected readonly List<List<Symbol>> _valueParameters = [];
|
||||
protected readonly List<List<Symbol>> ValueParameters = [];
|
||||
|
||||
public override void PreVisit(Subprogram subprogram)
|
||||
{
|
||||
|
@ -334,7 +313,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
|||
base.PreVisit(subprogramHead);
|
||||
|
||||
_parameters = null;
|
||||
_valueParameters.Clear();
|
||||
ValueParameters.Clear();
|
||||
}
|
||||
|
||||
public override void PostVisit(SubprogramHead subprogramHead)
|
||||
|
@ -351,7 +330,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
|||
|
||||
// 正序遍历_valueParameter
|
||||
// 倒序遍历其中的列表
|
||||
foreach (List<Symbol> children in _valueParameters)
|
||||
foreach (List<Symbol> children in ValueParameters)
|
||||
{
|
||||
foreach (Symbol symbol in children.AsEnumerable().Reverse())
|
||||
{
|
||||
|
@ -397,7 +376,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
|||
|
||||
valueParameter.IdentifierList.IsProcedure = true;
|
||||
_parameters = [];
|
||||
_valueParameters.Add(_parameters);
|
||||
ValueParameters.Add(_parameters);
|
||||
if (valueParameter.IsReference)
|
||||
{
|
||||
valueParameter.IdentifierList.IsReference = true;
|
||||
|
@ -496,72 +475,22 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
|||
public override void PostVisit(ProcedureCall 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) =>
|
||||
{
|
||||
// 检查procedure输入参数个数是否相符
|
||||
if (e.Parameters.Expressions.Count != functionType.Parameters.Count)
|
||||
if (ValidateProcedureCall(procedureCall.ProcedureId, e.Parameters.Expressions,
|
||||
out PascalFunctionType? functionType))
|
||||
{
|
||||
IsError = true;
|
||||
logger?.LogError("Procedure '{}' expects {} parameters but {} provided.",
|
||||
procedure.SymbolName,
|
||||
functionType.Parameters.Count,
|
||||
e.Parameters.Expressions.Count);
|
||||
return;
|
||||
procedureCall.ReturnType = functionType.ReturnType;
|
||||
}
|
||||
};
|
||||
|
||||
// 检查每个参数的类型与procedure参数定义类型是否相符
|
||||
foreach ((Expression expression, PascalParameterType parameterType) in e.Parameters.Expressions.Zip(
|
||||
functionType.Parameters))
|
||||
procedureCall.OnNoParameterGenerator += (_, _) =>
|
||||
{
|
||||
if (expression.ExpressionType != parameterType.ParameterType)
|
||||
if (ValidateProcedureCall(procedureCall.ProcedureId, [],
|
||||
out PascalFunctionType? functionType))
|
||||
{
|
||||
IsError = true;
|
||||
logger?.LogError("Parameter expect '{}' but '{}'",
|
||||
parameterType.ParameterType.TypeName, expression.ExpressionType);
|
||||
return;
|
||||
}
|
||||
procedureCall.ReturnType = functionType.ReturnType;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -569,10 +498,20 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
|||
public override void PostVisit(Variable variable)
|
||||
{
|
||||
base.PostVisit(variable);
|
||||
|
||||
if (SymbolTable.TryGetSymbol(variable.Identifier.IdentifierName, out Symbol? id))
|
||||
{
|
||||
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++)
|
||||
{
|
||||
if (variable.VariableType is PascalArrayType arrayType)
|
||||
|
@ -614,4 +553,90 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
|
|
|
@ -6,12 +6,12 @@ using Canon.Core.SemanticParser;
|
|||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnSimpleExpressionGeneratorEventArgs : EventArgs
|
||||
public class SimpleExpressionGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required SimpleExpression SimpleExpression { get; init; }
|
||||
}
|
||||
|
||||
public class OnRelationGeneratorEventArgs : EventArgs
|
||||
public class RelationGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required SimpleExpression Left { get; init; }
|
||||
|
||||
|
@ -76,12 +76,12 @@ public class Expression : NonTerminatedSyntaxNode
|
|||
/// <summary>
|
||||
/// 直接赋值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnSimpleExpressionGeneratorEventArgs>? OnSimpleExpressionGenerator;
|
||||
public event EventHandler<SimpleExpressionGeneratorEventArgs>? OnSimpleExpressionGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 关系产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnRelationGeneratorEventArgs>? OnRelationGenerator;
|
||||
public event EventHandler<RelationGeneratorEventArgs>? OnRelationGenerator;
|
||||
|
||||
private PascalType? _expressionType;
|
||||
|
||||
|
@ -111,14 +111,14 @@ public class Expression : NonTerminatedSyntaxNode
|
|||
{
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
OnSimpleExpressionGenerator?.Invoke(this, new OnSimpleExpressionGeneratorEventArgs
|
||||
OnSimpleExpressionGenerator?.Invoke(this, new SimpleExpressionGeneratorEventArgs
|
||||
{
|
||||
SimpleExpression = Children[0].Convert<SimpleExpression>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnRelationGenerator?.Invoke(this, new OnRelationGeneratorEventArgs
|
||||
OnRelationGenerator?.Invoke(this, new RelationGeneratorEventArgs
|
||||
{
|
||||
Left = Children[0].Convert<SimpleExpression>(),
|
||||
Operator = Children[1].Convert<RelationOperator>(),
|
||||
|
|
|
@ -1,43 +1,57 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnNumberGeneratorEventArgs : EventArgs
|
||||
public class NumberGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required NumberSemanticToken Token { get; init; }
|
||||
}
|
||||
|
||||
public class OnVariableGeneratorEventArgs : EventArgs
|
||||
public class VariableGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Variable Variable { get; init; }
|
||||
}
|
||||
|
||||
public class OnParethnesisGeneratorEventArgs : EventArgs
|
||||
public class ParethnesisGeneratorEventArgs : EventArgs
|
||||
{
|
||||
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 ExpressionList Parameters { get; init; }
|
||||
}
|
||||
|
||||
public class OnNotGeneratorEventArgs : EventArgs
|
||||
public class NotGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Factor Factor { get; init; }
|
||||
}
|
||||
|
||||
public class OnUminusGeneratorEventArgs : EventArgs
|
||||
public class UminusGeneratorEventArgs : EventArgs
|
||||
{
|
||||
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 override NonTerminatorType Type => NonTerminatorType.Factor;
|
||||
|
@ -57,32 +71,47 @@ public class Factor : NonTerminatedSyntaxNode
|
|||
/// <summary>
|
||||
/// 使用数值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnNumberGeneratorEventArgs>? OnNumberGenerator;
|
||||
public event EventHandler<NumberGeneratorEventArgs>? OnNumberGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用括号产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnParethnesisGeneratorEventArgs>? OnParethnesisGenerator;
|
||||
public event EventHandler<ParethnesisGeneratorEventArgs>? OnParethnesisGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用变量产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnVariableGeneratorEventArgs>? OnVariableGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用过程调用产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnProcedureCallGeneratorEventArgs>? OnProcedureCallGenerator;
|
||||
public event EventHandler<VariableGeneratorEventArgs>? OnVariableGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用否定产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnNotGeneratorEventArgs>? OnNotGenerator;
|
||||
public event EventHandler<NotGeneratorEventArgs>? OnNotGenerator;
|
||||
|
||||
/// <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;
|
||||
|
||||
|
@ -97,10 +126,7 @@ public class Factor : NonTerminatedSyntaxNode
|
|||
|
||||
return _factorType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_factorType = value;
|
||||
}
|
||||
set { _factorType = value; }
|
||||
}
|
||||
|
||||
public static Factor Create(List<SyntaxNodeBase> children)
|
||||
|
@ -112,51 +138,94 @@ public class Factor : NonTerminatedSyntaxNode
|
|||
{
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
//factor -> num
|
||||
if (Children[0].IsTerminated)
|
||||
{
|
||||
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||
|
||||
switch (token.TokenType)
|
||||
{
|
||||
// factor -> num
|
||||
case SemanticTokenType.Number:
|
||||
OnNumberGenerator?.Invoke(this,
|
||||
new OnNumberGeneratorEventArgs { Token = token.Convert<NumberSemanticToken>() });
|
||||
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
|
||||
{
|
||||
OnVariableGenerator?.Invoke(this,
|
||||
new OnVariableGeneratorEventArgs { Variable = Children[0].Convert<Variable>() });
|
||||
new VariableGeneratorEventArgs { Variable = Children[0].Convert<Variable>() });
|
||||
}
|
||||
}
|
||||
//factor -> ( expression )
|
||||
else if (Children.Count == 3)
|
||||
{
|
||||
TerminatedSyntaxNode terminatedSyntaxNode = Children[0].Convert<TerminatedSyntaxNode>();
|
||||
|
||||
// factor -> ( expression )
|
||||
if (terminatedSyntaxNode.Token.TokenType == SemanticTokenType.Delimiter)
|
||||
{
|
||||
OnParethnesisGenerator?.Invoke(this,
|
||||
new OnParethnesisGeneratorEventArgs { Expression = Children[1].Convert<Expression>() });
|
||||
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)
|
||||
{
|
||||
OnProcedureCallGenerator?.Invoke(this,
|
||||
new OnProcedureCallGeneratorEventArgs
|
||||
// factor -> id ( expressionList)
|
||||
OnProcedureCallGenerator?.Invoke(this, new ProcedureCallGeneratorEventArgs
|
||||
{
|
||||
ProcedureName =
|
||||
Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||
ProcedureName = Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||
Parameters = Children[2].Convert<ExpressionList>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||
Factor factor = Children[1].Convert<Factor>();
|
||||
|
||||
if (token.TokenType == SemanticTokenType.Keyword)
|
||||
{
|
||||
// factor -> not factor
|
||||
OnNotGenerator?.Invoke(this, new OnNotGeneratorEventArgs { Factor = factor });
|
||||
OnNotGenerator?.Invoke(this, new NotGeneratorEventArgs { Factor = factor });
|
||||
}
|
||||
else
|
||||
{
|
||||
// factor -> uminus factor
|
||||
OnUminusGenerator?.Invoke(this, new OnUminusGeneratorEventArgs { Factor = factor });
|
||||
OperatorSemanticToken operatorSemanticToken = token.Convert<OperatorSemanticToken>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,14 @@ using Canon.Core.SemanticParser;
|
|||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnIdentifierGeneratorEventArgs : EventArgs
|
||||
public class IdentifierGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required IdentifierSemanticToken IdentifierToken { get; init; }
|
||||
|
||||
public required IdentifierList IdentifierList { get; init; }
|
||||
}
|
||||
|
||||
public class OnTypeGeneratorEventArgs : EventArgs
|
||||
public class TypeGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required TypeSyntaxNode TypeSyntaxNode { get; init; }
|
||||
}
|
||||
|
@ -66,9 +66,9 @@ public class IdentifierList : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
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)
|
||||
{
|
||||
|
@ -80,11 +80,11 @@ public class IdentifierList : NonTerminatedSyntaxNode
|
|||
if (Children.Count == 2)
|
||||
{
|
||||
OnTypeGenerator?.Invoke(this,
|
||||
new OnTypeGeneratorEventArgs { TypeSyntaxNode = Children[1].Convert<TypeSyntaxNode>() });
|
||||
new TypeGeneratorEventArgs { TypeSyntaxNode = Children[1].Convert<TypeSyntaxNode>() });
|
||||
}
|
||||
else
|
||||
{
|
||||
OnIdentifierGenerator?.Invoke(this, new OnIdentifierGeneratorEventArgs
|
||||
OnIdentifierGenerator?.Invoke(this, new IdentifierGeneratorEventArgs
|
||||
{
|
||||
IdentifierToken = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||
IdentifierList = Children[2].Convert<IdentifierList>()
|
||||
|
|
|
@ -4,7 +4,7 @@ using Canon.Core.SemanticParser;
|
|||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnIndexGeneratorEventArgs : EventArgs
|
||||
public class IndexGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required ExpressionList IndexParameters { get; init; }
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
|
|||
/// <summary>
|
||||
/// 使用了索引产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnIndexGeneratorEventArgs>? OnIndexGenerator;
|
||||
public event EventHandler<IndexGeneratorEventArgs>? OnIndexGenerator;
|
||||
|
||||
public static IdentifierVarPart Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
|
|||
{
|
||||
if (Children.Count == 3)
|
||||
{
|
||||
OnIndexGenerator?.Invoke(this, new OnIndexGeneratorEventArgs()
|
||||
OnIndexGenerator?.Invoke(this, new IndexGeneratorEventArgs()
|
||||
{
|
||||
IndexParameters = Children[1].Convert<ExpressionList>()
|
||||
});
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnParameterGeneratorEventArgs : EventArgs
|
||||
public class ParameterGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required ExpressionList Parameters { get; init; }
|
||||
}
|
||||
|
||||
public class NoParameterGeneratorEventArgs : EventArgs;
|
||||
|
||||
public class ProcedureCall : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.ProcedureCall;
|
||||
|
@ -19,7 +22,31 @@ public class ProcedureCall : NonTerminatedSyntaxNode
|
|||
/// <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)
|
||||
{
|
||||
|
@ -42,12 +69,17 @@ public class ProcedureCall : NonTerminatedSyntaxNode
|
|||
{
|
||||
if (Children.Count == 4)
|
||||
{
|
||||
OnParameterGenerator?.Invoke(this, new OnParameterGeneratorEventArgs
|
||||
OnParameterGenerator?.Invoke(this, new ParameterGeneratorEventArgs
|
||||
{
|
||||
Parameters = Children[2].Convert<ExpressionList>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnNoParameterGenerator?.Invoke(this, new NoParameterGeneratorEventArgs());
|
||||
}
|
||||
|
||||
OnParameterGenerator = null;
|
||||
OnNoParameterGenerator = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ using Canon.Core.SemanticParser;
|
|||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnTermGeneratorEventArgs : EventArgs
|
||||
public class TermGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Term Term { get; init; }
|
||||
}
|
||||
|
||||
public class OnAddGeneratorEventArgs : EventArgs
|
||||
public class AddGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required SimpleExpression Left { get; init; }
|
||||
|
||||
|
@ -38,12 +38,12 @@ public class SimpleExpression : NonTerminatedSyntaxNode
|
|||
/// <summary>
|
||||
/// 直接赋值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnTermGeneratorEventArgs>? OnTermGenerator;
|
||||
public event EventHandler<TermGeneratorEventArgs>? OnTermGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 加法产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnAddGeneratorEventArgs>? OnAddGenerator;
|
||||
public event EventHandler<AddGeneratorEventArgs>? OnAddGenerator;
|
||||
|
||||
private PascalType? _simpleExpressionType;
|
||||
|
||||
|
@ -73,14 +73,14 @@ public class SimpleExpression : NonTerminatedSyntaxNode
|
|||
{
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
OnTermGenerator?.Invoke(this, new OnTermGeneratorEventArgs
|
||||
OnTermGenerator?.Invoke(this, new TermGeneratorEventArgs
|
||||
{
|
||||
Term = Children[0].Convert<Term>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnAddGenerator?.Invoke(this, new OnAddGeneratorEventArgs
|
||||
OnAddGenerator?.Invoke(this, new AddGeneratorEventArgs
|
||||
{
|
||||
Left = Children[0].Convert<SimpleExpression>(),
|
||||
Operator = Children[1].Convert<AddOperator>(),
|
||||
|
|
|
@ -5,21 +5,14 @@ using Canon.Core.LexicalParser;
|
|||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnAssignGeneratorEventArgs : EventArgs
|
||||
public class AssignGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Variable Variable { get; init; }
|
||||
|
||||
public required Expression Expression { get; init; }
|
||||
}
|
||||
|
||||
public class OnReturnGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required IdentifierSemanticToken FunctionName { get; set; }
|
||||
|
||||
public required Expression Expression { get; init; }
|
||||
}
|
||||
|
||||
public class OnIfGeneratorEventArgs : EventArgs
|
||||
public class IfGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Expression Condition { get; init; }
|
||||
|
||||
|
@ -28,7 +21,7 @@ public class OnIfGeneratorEventArgs : EventArgs
|
|||
public required ElsePart ElseSentence { get; init; }
|
||||
}
|
||||
|
||||
public class OnForGeneratorEventArgs : EventArgs
|
||||
public class ForGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required IdentifierSemanticToken Iterator { get; init; }
|
||||
|
||||
|
@ -58,22 +51,17 @@ public class Statement : NonTerminatedSyntaxNode
|
|||
/// <summary>
|
||||
/// 使用赋值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnAssignGeneratorEventArgs>? OnAssignGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用返回产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnReturnGeneratorEventArgs>? OnReturnGenerator;
|
||||
public event EventHandler<AssignGeneratorEventArgs>? OnAssignGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用If产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnIfGeneratorEventArgs>? OnIfGenerator;
|
||||
public event EventHandler<IfGeneratorEventArgs>? OnIfGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用For产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnForGeneratorEventArgs>? OnForGenerator;
|
||||
public event EventHandler<ForGeneratorEventArgs>? OnForGenerator;
|
||||
|
||||
public static Statement Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
|
@ -84,26 +72,16 @@ public class Statement : NonTerminatedSyntaxNode
|
|||
{
|
||||
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>(),
|
||||
Expression = Children[2].Convert<Expression>()
|
||||
Variable = Children[0].Convert<Variable>(), 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)
|
||||
{
|
||||
OnIfGenerator?.Invoke(this, new OnIfGeneratorEventArgs
|
||||
OnIfGenerator?.Invoke(this,
|
||||
new IfGeneratorEventArgs
|
||||
{
|
||||
Condition = Children[1].Convert<Expression>(),
|
||||
Sentence = Children[3].Convert<Statement>(),
|
||||
|
@ -112,7 +90,8 @@ public class Statement : NonTerminatedSyntaxNode
|
|||
}
|
||||
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>(),
|
||||
|
|
|
@ -4,9 +4,9 @@ using Canon.Core.LexicalParser;
|
|||
|
||||
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; }
|
||||
}
|
||||
|
@ -40,9 +40,9 @@ public class SubprogramHead : NonTerminatedSyntaxNode
|
|||
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)
|
||||
{
|
||||
|
@ -71,12 +71,12 @@ public class SubprogramHead : NonTerminatedSyntaxNode
|
|||
{
|
||||
if (IsProcedure)
|
||||
{
|
||||
OnProcedureGenerator?.Invoke(this, new OnProcedureGeneratorEventArgs());
|
||||
OnProcedureGenerator?.Invoke(this, new ProcedureGeneratorEventArgs());
|
||||
}
|
||||
else
|
||||
{
|
||||
OnFunctionGenerator?.Invoke(this,
|
||||
new OnFunctionGeneratorEventArgs { ReturnType = Children[4].Convert<BasicType>() });
|
||||
new FunctionGeneratorEventArgs { ReturnType = Children[4].Convert<BasicType>() });
|
||||
}
|
||||
|
||||
OnProcedureGenerator = null;
|
||||
|
|
|
@ -5,7 +5,7 @@ using Canon.Core.LexicalParser;
|
|||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public abstract class SyntaxNodeBase : ICCodeGenerator
|
||||
public abstract class SyntaxNodeBase
|
||||
{
|
||||
public abstract bool IsTerminated { get; }
|
||||
|
||||
|
@ -25,13 +25,6 @@ public abstract class SyntaxNodeBase : ICCodeGenerator
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 语法树节点基类对于生成C代码的默认实现
|
||||
/// </summary>
|
||||
public virtual void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return IsTerminated.ToString();
|
||||
|
|
|
@ -5,12 +5,12 @@ using Canon.Core.SemanticParser;
|
|||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnFactorGeneratorEventArgs : EventArgs
|
||||
public class FactorGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Factor Factor { get; init; }
|
||||
}
|
||||
|
||||
public class OnMultiplyGeneratorEventArgs : EventArgs
|
||||
public class MultiplyGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Term Left { get; init; }
|
||||
|
||||
|
@ -38,12 +38,12 @@ public class Term : NonTerminatedSyntaxNode
|
|||
/// <summary>
|
||||
/// 直接赋值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnFactorGeneratorEventArgs>? OnFactorGenerator;
|
||||
public event EventHandler<FactorGeneratorEventArgs>? OnFactorGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 乘法产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnMultiplyGeneratorEventArgs>? OnMultiplyGenerator;
|
||||
public event EventHandler<MultiplyGeneratorEventArgs>? OnMultiplyGenerator;
|
||||
|
||||
private PascalType? _termType;
|
||||
|
||||
|
@ -73,14 +73,14 @@ public class Term : NonTerminatedSyntaxNode
|
|||
{
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
OnFactorGenerator?.Invoke(this, new OnFactorGeneratorEventArgs
|
||||
OnFactorGenerator?.Invoke(this, new FactorGeneratorEventArgs
|
||||
{
|
||||
Factor = Children[0].Convert<Factor>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnMultiplyGenerator?.Invoke(this, new OnMultiplyGeneratorEventArgs
|
||||
OnMultiplyGenerator?.Invoke(this, new MultiplyGeneratorEventArgs
|
||||
{
|
||||
Left = Children[0].Convert<Term>(),
|
||||
Operator = Children[1].Convert<MultiplyOperator>(),
|
||||
|
|
|
@ -5,12 +5,12 @@ using Canon.Core.SemanticParser;
|
|||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnBasicTypeGeneratorEventArgs : EventArgs
|
||||
public class BasicTypeGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required BasicType BasicType { get; init; }
|
||||
}
|
||||
|
||||
public class OnArrayTypeGeneratorEventArgs : EventArgs
|
||||
public class ArrayTypeGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Period Period { get; init; }
|
||||
|
||||
|
@ -33,9 +33,9 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
|
|||
RaiseEvent();
|
||||
}
|
||||
|
||||
public event EventHandler<OnBasicTypeGeneratorEventArgs>? OnBasicTypeGenerator;
|
||||
public event EventHandler<BasicTypeGeneratorEventArgs>? OnBasicTypeGenerator;
|
||||
|
||||
public event EventHandler<OnArrayTypeGeneratorEventArgs>? OnArrayTypeGenerator;
|
||||
public event EventHandler<ArrayTypeGeneratorEventArgs>? OnArrayTypeGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 是否在过程定义中使用
|
||||
|
@ -74,14 +74,14 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
|
|||
{
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
OnBasicTypeGenerator?.Invoke(this, new OnBasicTypeGeneratorEventArgs
|
||||
OnBasicTypeGenerator?.Invoke(this, new BasicTypeGeneratorEventArgs
|
||||
{
|
||||
BasicType = Children[0].Convert<BasicType>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnArrayTypeGenerator?.Invoke(this, new OnArrayTypeGeneratorEventArgs
|
||||
OnArrayTypeGenerator?.Invoke(this, new ArrayTypeGeneratorEventArgs
|
||||
{
|
||||
Period = Children[2].Convert<Period>(),
|
||||
BasicType = Children[5].Convert<BasicType>()
|
||||
|
|
|
@ -30,6 +30,7 @@ public class BasicTest
|
|||
|
||||
string result = visitor.Builder.Build();
|
||||
_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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,13 +72,37 @@ public class SubprogramTests
|
|||
|
||||
string result = visitor.Builder.Build();
|
||||
_output.WriteLine(result);
|
||||
Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nbool b, a;" +
|
||||
"\nint func1(int* a, int b, double c)\n{\nint func1;\n" +
|
||||
"{\n(*a) = b + c;\nfunc1 = (*a) * 3;\n;\n}\nreturn func1;\n}\n" +
|
||||
"char func2(bool* a, bool* b, char c[][6])\n{\nchar func2;\n" +
|
||||
"{\n(*a) = (*b) && (!(*b));\nfunc2 = c[5-0][8-3];\n;\n}\nreturn func2;\n}" +
|
||||
"\nint main()\n{\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
|
||||
Assert.Equal("""
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
bool b, a;
|
||||
int func1(int* a, int b, double c)
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,4 +161,86 @@ public class PascalGrammarTests
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 Xunit.Abstractions;
|
||||
|
||||
|
@ -159,11 +159,6 @@ public class SimpleGrammarWithEmptyTests(ITestOutputHelper testOutputHelper)
|
|||
};
|
||||
|
||||
Grammar grammar = builder.Build();
|
||||
IGrammarParser parser = grammar.ToGrammarParser();
|
||||
|
||||
ITransformer transformer1 = parser.BeginTransformer;
|
||||
Assert.Equal(3, transformer1.ShiftTable.Count);
|
||||
Assert.Single(transformer1.ReduceTable);
|
||||
Assert.Contains(new NonTerminator(NonTerminatorType.ProgramStruct),transformer1.ShiftTable);
|
||||
Assert.Throws<ReduceAndShiftConflictException>(() => grammar.ToGrammarParser());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ public class KeywordTypeTests
|
|||
[InlineData("to", KeywordType.To)]
|
||||
[InlineData("do", KeywordType.Do)]
|
||||
[InlineData("DO", KeywordType.Do)]
|
||||
[InlineData("true", KeywordType.True)]
|
||||
[InlineData("false", KeywordType.False)]
|
||||
public void SmokeTest(string input, KeywordType type)
|
||||
{
|
||||
IEnumerable<SemanticToken> tokensEnumerable = _lexer.Tokenize(new StringSourceReader(input));
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Canon.Tests.SemanticTests;
|
|||
|
||||
public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
private readonly TestLogger<TypeCheckVisitor> _logger = new(testOutputHelper);
|
||||
private readonly TestLogger _logger = new(testOutputHelper);
|
||||
|
||||
[Fact]
|
||||
public void ConstTypeTest()
|
||||
|
@ -549,6 +549,92 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
|||
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)
|
||||
{
|
||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||
|
|
|
@ -1,24 +1,16 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Canon.Core.Abstractions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
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,
|
||||
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 void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state) where TState : notnull
|
||||
{
|
||||
return this;
|
||||
}
|
||||
public string Build() => string.Empty;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ def compile_files():
|
|||
print("Info: compile ", file)
|
||||
if not (Path("open_set") / file.stem).exists():
|
||||
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_binary = "open_set/" + file.stem + ".out"
|
||||
os.system("gcc " + c_file + " -o " + c_binary)
|
||||
|
|
Loading…
Reference in New Issue
Block a user