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
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
View File

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

View File

@ -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
}

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.Enums;
using Canon.Core.Exceptions;
namespace Canon.Core.GrammarParser;
@ -45,13 +47,23 @@ 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);
}
}
}
// 生成移进的迁移表
foreach (KeyValuePair<TerminatorBase,LrState> pair in state.Transformer)
foreach (KeyValuePair<TerminatorBase, LrState> pair in state.Transformer)
{
ITransformer targetTransformer;
if (transformers.TryGetValue(pair.Value, out Transformer? oldTransformer2))
@ -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);
}
}

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 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 ( ExpressionList )
// | 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)
]
]
},

View File

@ -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)

View File

@ -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 += (_, _) =>
{

View File

@ -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

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.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;
}
}

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)
{
visitor.PreVisit(this);

View File

@ -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>(),

View File

@ -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;
}
}
}

View File

@ -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>()

View File

@ -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>()
});

View File

@ -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;
}
}

View File

@ -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>(),

View File

@ -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>(),

View File

@ -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;

View File

@ -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();

View File

@ -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>(),

View File

@ -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>()

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

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 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());
}
}

View File

@ -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));

View File

@ -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);

View File

@ -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;
}

View File

@ -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)