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
|
name: Integration Test
|
||||||
on:
|
on: [push]
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Open-Set-Test:
|
Open-Set-Test:
|
||||||
|
@ -18,8 +15,10 @@ jobs:
|
||||||
save-always: true
|
save-always: true
|
||||||
- name: Build binary file
|
- name: Build binary file
|
||||||
run: |
|
run: |
|
||||||
|
cd ./Canon.Console
|
||||||
dotnet publish
|
dotnet publish
|
||||||
cp ./Canon.Console/bin/Release/net8.0/linux-x64/publish/Canon.Console ./pacss
|
cd ..
|
||||||
|
cp ./Canon.Console/bin/Release/net8.0/linux-x64/publish/Canon.Console ./pascc
|
||||||
- name: Build open set binary
|
- name: Build open set binary
|
||||||
run: |
|
run: |
|
||||||
python scripts/integration_test.py run
|
python scripts/integration_test.py run
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -485,3 +485,6 @@ $RECYCLE.BIN/
|
||||||
|
|
||||||
# Database Source File
|
# Database Source File
|
||||||
*.db
|
*.db
|
||||||
|
|
||||||
|
# Pascall C Compiler
|
||||||
|
pascc
|
||||||
|
|
|
@ -62,7 +62,9 @@ public enum KeywordType
|
||||||
Not,
|
Not,
|
||||||
Mod,
|
Mod,
|
||||||
And,
|
And,
|
||||||
Or
|
Or,
|
||||||
|
True,
|
||||||
|
False
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum OperatorType
|
public enum OperatorType
|
||||||
|
@ -99,11 +101,3 @@ public enum StateType
|
||||||
Unknown,
|
Unknown,
|
||||||
Done
|
Done
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum BasicIdType
|
|
||||||
{
|
|
||||||
Int,
|
|
||||||
Real,
|
|
||||||
Char,
|
|
||||||
Bool
|
|
||||||
}
|
|
||||||
|
|
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.Abstractions;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.Exceptions;
|
||||||
|
|
||||||
namespace Canon.Core.GrammarParser;
|
namespace Canon.Core.GrammarParser;
|
||||||
|
|
||||||
|
@ -45,13 +47,23 @@ public class Grammar
|
||||||
{
|
{
|
||||||
if (expression.Pos == expression.Right.Count)
|
if (expression.Pos == expression.Right.Count)
|
||||||
{
|
{
|
||||||
transformer.ReduceTable.TryAdd(expression.LookAhead, new ReduceInformation(
|
if (transformer.ShiftTable.ContainsKey(expression.LookAhead))
|
||||||
expression.Right.Count, expression.Left));
|
{
|
||||||
|
throw new ReduceAndShiftConflictException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!transformer.ReduceTable.TryAdd(expression.LookAhead,
|
||||||
|
new ReduceInformation(expression.Right.Count, expression.Left)))
|
||||||
|
{
|
||||||
|
// 发生归约-归约冲突
|
||||||
|
throw new ReduceConflictException(state, expression.LookAhead, expression.Left,
|
||||||
|
transformer.ReduceTable[expression.LookAhead].Left);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成移进的迁移表
|
// 生成移进的迁移表
|
||||||
foreach (KeyValuePair<TerminatorBase,LrState> pair in state.Transformer)
|
foreach (KeyValuePair<TerminatorBase, LrState> pair in state.Transformer)
|
||||||
{
|
{
|
||||||
ITransformer targetTransformer;
|
ITransformer targetTransformer;
|
||||||
if (transformers.TryGetValue(pair.Value, out Transformer? oldTransformer2))
|
if (transformers.TryGetValue(pair.Value, out Transformer? oldTransformer2))
|
||||||
|
@ -64,7 +76,19 @@ public class Grammar
|
||||||
transformers.Add(pair.Value, newTransformer);
|
transformers.Add(pair.Value, newTransformer);
|
||||||
targetTransformer = newTransformer;
|
targetTransformer = newTransformer;
|
||||||
}
|
}
|
||||||
transformer.ShiftTable.TryAdd(pair.Key, targetTransformer);
|
|
||||||
|
// 检测移进-归约冲突
|
||||||
|
if (pair.Key.IsTerminated)
|
||||||
|
{
|
||||||
|
Terminator terminator = (Terminator)pair.Key;
|
||||||
|
// hack 对于ElsePart的移进-归约冲突
|
||||||
|
if (terminator != new Terminator(KeywordType.Else) && transformer.ReduceTable.ContainsKey(terminator))
|
||||||
|
{
|
||||||
|
throw new ReduceAndShiftConflictException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transformer.ShiftTable.Add(pair.Key, targetTransformer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ public static class PascalGrammar
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// ConstValue -> +num | -num | num | 'letter'
|
// ConstValue -> +num | -num | num | 'letter' | true | false
|
||||||
new NonTerminator(NonTerminatorType.ConstValue), [
|
new NonTerminator(NonTerminatorType.ConstValue), [
|
||||||
[
|
[
|
||||||
new Terminator(OperatorType.Plus), Terminator.NumberTerminator
|
new Terminator(OperatorType.Plus), Terminator.NumberTerminator
|
||||||
|
@ -114,6 +114,12 @@ public static class PascalGrammar
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
Terminator.CharacterTerminator,
|
Terminator.CharacterTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.True)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.False)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -245,6 +251,10 @@ public static class PascalGrammar
|
||||||
[
|
[
|
||||||
Terminator.EmptyTerminator,
|
Terminator.EmptyTerminator,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
|
new Terminator(DelimiterType.RightParenthesis)
|
||||||
|
],
|
||||||
[
|
[
|
||||||
new Terminator(DelimiterType.LeftParenthesis),
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
new NonTerminator(NonTerminatorType.ParameterList),
|
new NonTerminator(NonTerminatorType.ParameterList),
|
||||||
|
@ -334,13 +344,10 @@ public static class PascalGrammar
|
||||||
{
|
{
|
||||||
// Statement -> ε
|
// Statement -> ε
|
||||||
// | Variable AssignOp Expression
|
// | Variable AssignOp Expression
|
||||||
// | FuncId AssignOp Expression
|
|
||||||
// | ProcedureCall
|
// | ProcedureCall
|
||||||
// | CompoundStatement
|
// | CompoundStatement
|
||||||
// | if Expression then Statement ElsePart
|
// | if Expression then Statement ElsePart
|
||||||
// | for id AssignOp Expression to Expression do Statement
|
// | for id AssignOp Expression to Expression do Statement
|
||||||
// | read ( VariableList )
|
|
||||||
// | write( ExpressionList )
|
|
||||||
// 注意这里 read 和 write 作为普通的函数调用处理了
|
// 注意这里 read 和 write 作为普通的函数调用处理了
|
||||||
// 因此下面并没有单独声明
|
// 因此下面并没有单独声明
|
||||||
new NonTerminator(NonTerminatorType.Statement), [
|
new NonTerminator(NonTerminatorType.Statement), [
|
||||||
|
@ -354,12 +361,6 @@ public static class PascalGrammar
|
||||||
new Terminator(OperatorType.Assign),
|
new Terminator(OperatorType.Assign),
|
||||||
new NonTerminator(NonTerminatorType.Expression)
|
new NonTerminator(NonTerminatorType.Expression)
|
||||||
],
|
],
|
||||||
[
|
|
||||||
// FuncId AssignOp Expression
|
|
||||||
Terminator.IdentifierTerminator,
|
|
||||||
new Terminator(OperatorType.Assign),
|
|
||||||
new NonTerminator(NonTerminatorType.Expression)
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
// ProcedureCall
|
// ProcedureCall
|
||||||
new NonTerminator(NonTerminatorType.ProcedureCall)
|
new NonTerminator(NonTerminatorType.ProcedureCall)
|
||||||
|
@ -426,11 +427,16 @@ public static class PascalGrammar
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// ProcedureCall -> id | id ( ExpressionList )
|
// ProcedureCall -> id | id() | id ( ExpressionList )
|
||||||
new NonTerminator(NonTerminatorType.ProcedureCall), [
|
new NonTerminator(NonTerminatorType.ProcedureCall), [
|
||||||
[
|
[
|
||||||
Terminator.IdentifierTerminator,
|
Terminator.IdentifierTerminator,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
|
new Terminator(DelimiterType.RightParenthesis)
|
||||||
|
],
|
||||||
[
|
[
|
||||||
Terminator.IdentifierTerminator,
|
Terminator.IdentifierTerminator,
|
||||||
new Terminator(DelimiterType.LeftParenthesis),
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
|
@ -506,9 +512,13 @@ public static class PascalGrammar
|
||||||
{
|
{
|
||||||
// Factor -> num | Variable
|
// Factor -> num | Variable
|
||||||
// | ( Expression )
|
// | ( Expression )
|
||||||
// | id ( ExpressionList )
|
// | id ()
|
||||||
|
// | id (ExpressionList)
|
||||||
// | not Factor
|
// | not Factor
|
||||||
// | minus Factor
|
// | - Factor
|
||||||
|
// | + Factor
|
||||||
|
// | true
|
||||||
|
// | false
|
||||||
new NonTerminator(NonTerminatorType.Factor), [
|
new NonTerminator(NonTerminatorType.Factor), [
|
||||||
[
|
[
|
||||||
Terminator.NumberTerminator,
|
Terminator.NumberTerminator,
|
||||||
|
@ -521,6 +531,11 @@ public static class PascalGrammar
|
||||||
new NonTerminator(NonTerminatorType.Expression),
|
new NonTerminator(NonTerminatorType.Expression),
|
||||||
new Terminator(DelimiterType.RightParenthesis)
|
new Terminator(DelimiterType.RightParenthesis)
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
|
new Terminator(DelimiterType.RightParenthesis)
|
||||||
|
],
|
||||||
[
|
[
|
||||||
Terminator.IdentifierTerminator,
|
Terminator.IdentifierTerminator,
|
||||||
new Terminator(DelimiterType.LeftParenthesis),
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
|
@ -534,6 +549,16 @@ public static class PascalGrammar
|
||||||
[
|
[
|
||||||
new Terminator(OperatorType.Minus),
|
new Terminator(OperatorType.Minus),
|
||||||
new NonTerminator(NonTerminatorType.Factor)
|
new NonTerminator(NonTerminatorType.Factor)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Plus),
|
||||||
|
new NonTerminator(NonTerminatorType.Factor)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.True)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.False)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,7 +31,9 @@ public static class LexRules
|
||||||
{ "not", KeywordType.Not },
|
{ "not", KeywordType.Not },
|
||||||
{ "mod", KeywordType.Mod },
|
{ "mod", KeywordType.Mod },
|
||||||
{ "and", KeywordType.And },
|
{ "and", KeywordType.And },
|
||||||
{ "or", KeywordType.Or }
|
{ "or", KeywordType.Or },
|
||||||
|
{ "true", KeywordType.True },
|
||||||
|
{ "false", KeywordType.False }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static bool GetKeywordTypeByKeywprd(string keyword, out KeywordType type)
|
public static bool GetKeywordTypeByKeywprd(string keyword, out KeywordType type)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using Canon.Core.Abstractions;
|
||||||
using Canon.Core.CodeGenerators;
|
using Canon.Core.CodeGenerators;
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
@ -7,7 +8,7 @@ using BasicType = Canon.Core.SyntaxNodes.BasicType;
|
||||||
|
|
||||||
namespace Canon.Core.SemanticParser;
|
namespace Canon.Core.SemanticParser;
|
||||||
|
|
||||||
public class CCodeGenerateVisitor : TypeCheckVisitor
|
public class CCodeGenerateVisitor(ICompilerLogger? logger = null) : TypeCheckVisitor(logger)
|
||||||
{
|
{
|
||||||
public CCodeBuilder Builder { get; } = new();
|
public CCodeBuilder Builder { get; } = new();
|
||||||
|
|
||||||
|
@ -142,7 +143,7 @@ public class CCodeGenerateVisitor : TypeCheckVisitor
|
||||||
Builder.AddString("(");
|
Builder.AddString("(");
|
||||||
List<string> parametersInfo = new();
|
List<string> parametersInfo = new();
|
||||||
|
|
||||||
foreach (List<Symbol> children in _valueParameters)
|
foreach (List<Symbol> children in ValueParameters)
|
||||||
{
|
{
|
||||||
foreach (Symbol symbol in children.AsEnumerable().Reverse())
|
foreach (Symbol symbol in children.AsEnumerable().Reverse())
|
||||||
{
|
{
|
||||||
|
@ -432,10 +433,6 @@ public class CCodeGenerateVisitor : TypeCheckVisitor
|
||||||
token.ParseAsReal().ToString(CultureInfo.InvariantCulture);
|
token.ParseAsReal().ToString(CultureInfo.InvariantCulture);
|
||||||
Builder.AddString(num);
|
Builder.AddString(num);
|
||||||
};
|
};
|
||||||
factor.OnProcedureCallGenerator += (_, _) =>
|
|
||||||
{
|
|
||||||
Builder.AddString(")");
|
|
||||||
};
|
|
||||||
factor.OnNotGenerator += (_, _) =>
|
factor.OnNotGenerator += (_, _) =>
|
||||||
{
|
{
|
||||||
Builder.AddString(")");
|
Builder.AddString(")");
|
||||||
|
@ -449,25 +446,10 @@ public class CCodeGenerateVisitor : TypeCheckVisitor
|
||||||
public override void PreVisit(Factor factor)
|
public override void PreVisit(Factor factor)
|
||||||
{
|
{
|
||||||
base.PreVisit(factor);
|
base.PreVisit(factor);
|
||||||
factor.OnProcedureCallGenerator += (_, e) =>
|
|
||||||
{
|
|
||||||
Builder.AddString(e.ProcedureName.IdentifierName + "(");
|
|
||||||
SymbolTable.TryGetParent(out var parentTable);
|
|
||||||
parentTable ??= SymbolTable;
|
|
||||||
|
|
||||||
parentTable.TryGetSymbol(e.ProcedureName.IdentifierName, out var symbol);
|
|
||||||
if (symbol == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Parameters.ParameterTypes.AddRange(symbol.SymbolType.Convert<PascalFunctionType>().Parameters);
|
|
||||||
e.Parameters.IsParamList = true;
|
|
||||||
e.Parameters.Expression.LastParam = true;
|
|
||||||
};
|
|
||||||
factor.OnNotGenerator += (_, _) =>
|
factor.OnNotGenerator += (_, _) =>
|
||||||
{
|
{
|
||||||
Builder.AddString("(!");
|
Builder.AddString("(~");
|
||||||
};
|
};
|
||||||
factor.OnUminusGenerator += (_, _) =>
|
factor.OnUminusGenerator += (_, _) =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,11 @@ public class PascalFunctionType(List<PascalParameterType> parameters, PascalType
|
||||||
|
|
||||||
public PascalType ReturnType { get; } = returnType;
|
public PascalType ReturnType { get; } = returnType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pascal核心库函数的类型
|
||||||
|
/// </summary>
|
||||||
|
public static PascalFunctionType CoreFuntionType => new PascalFunctionType([], PascalBasicType.Void);
|
||||||
|
|
||||||
public override string TypeName
|
public override string TypeName
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Abstractions;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Canon.Core.Abstractions;
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
using Canon.Core.SyntaxNodes;
|
using Canon.Core.SyntaxNodes;
|
||||||
|
@ -7,8 +8,11 @@ using Expression = Canon.Core.SyntaxNodes.Expression;
|
||||||
|
|
||||||
namespace Canon.Core.SemanticParser;
|
namespace Canon.Core.SemanticParser;
|
||||||
|
|
||||||
public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : SyntaxNodeVisitor
|
public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisitor
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 当前遍历阶段的符号表
|
||||||
|
/// </summary>
|
||||||
public SymbolTable SymbolTable { get; private set; } = new();
|
public SymbolTable SymbolTable { get; private set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -91,88 +95,63 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// factor -> true | false
|
||||||
|
factor.OnBooleanGenerator += (_, _) => { factor.FactorType = PascalBasicType.Boolean; };
|
||||||
|
|
||||||
// factor -> variable
|
// factor -> variable
|
||||||
factor.OnVariableGenerator += (_, e) => { factor.FactorType = e.Variable.VariableType; };
|
factor.OnVariableGenerator += (_, e) => { factor.FactorType = e.Variable.VariableType; };
|
||||||
|
|
||||||
// factor -> (expression)
|
// factor -> (expression)
|
||||||
factor.OnParethnesisGenerator += (_, e) => { factor.FactorType = e.Expression.ExpressionType; };
|
factor.OnParethnesisGenerator += (_, e) => { factor.FactorType = e.Expression.ExpressionType; };
|
||||||
|
|
||||||
// factor -> id (expression_list)
|
// factor -> id ()
|
||||||
factor.OnProcedureCallGenerator += (_, e) =>
|
factor.OnNoParameterProcedureCallGenerator += (_, e) =>
|
||||||
{
|
{
|
||||||
if (!SymbolTable.TryGetSymbol(e.ProcedureName.IdentifierName, out Symbol? procedure))
|
if (ValidateProcedureCall(e.ProcedureName, [], out PascalFunctionType? functionType))
|
||||||
{
|
{
|
||||||
IsError = true;
|
if (functionType.ReturnType != PascalBasicType.Void)
|
||||||
logger?.LogError("Procedure '{}' does not define.", e.ProcedureName.IdentifierName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PascalFunctionType? functionType = procedure.SymbolType as PascalFunctionType;
|
|
||||||
if (functionType is null)
|
|
||||||
{
|
|
||||||
if (SymbolTable.TryGetParent(out SymbolTable? parent))
|
|
||||||
{
|
{
|
||||||
if (parent.TryGetSymbol(e.ProcedureName.IdentifierName, out procedure))
|
factor.FactorType = functionType.ReturnType;
|
||||||
{
|
|
||||||
functionType = procedure.SymbolType as PascalFunctionType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (functionType is null)
|
|
||||||
{
|
|
||||||
IsError = true;
|
|
||||||
logger?.LogError("'{}' is not call able.", e.ProcedureName.IdentifierName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (functionType.ReturnType == PascalBasicType.Void)
|
|
||||||
{
|
|
||||||
IsError = true;
|
|
||||||
logger?.LogError("Procedure '{}' returns void.", e.ProcedureName.IdentifierName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
factor.FactorType = functionType.ReturnType;
|
|
||||||
|
|
||||||
if (e.Parameters.Expressions.Count != functionType.Parameters.Count)
|
|
||||||
{
|
|
||||||
IsError = true;
|
|
||||||
logger?.LogError("Procedure '{}' expects {} parameters but {} provided.",
|
|
||||||
e.ProcedureName.IdentifierName,
|
|
||||||
functionType.Parameters.Count,
|
|
||||||
e.Parameters.Expressions.Count);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ((Expression expression, PascalParameterType parameterType) in e.Parameters.Expressions.Zip(
|
|
||||||
functionType.Parameters))
|
|
||||||
{
|
|
||||||
if (expression.ExpressionType != parameterType.ParameterType)
|
|
||||||
{
|
|
||||||
IsError = true;
|
|
||||||
logger?.LogError("Parameter expect '{}' but '{}'",
|
|
||||||
parameterType.ParameterType.TypeName, expression.ExpressionType);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("The procedure '{}' returns void.", e.ProcedureName.IdentifierName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
factor.FactorType = PascalBasicType.Void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// factor -> factor
|
// factor -> id ( ExpressionList)
|
||||||
factor.OnNotGenerator += (_, e) =>
|
factor.OnProcedureCallGenerator += (_, e) =>
|
||||||
{
|
{
|
||||||
if (e.Factor.FactorType != PascalBasicType.Boolean)
|
if (ValidateProcedureCall(e.ProcedureName, e.Parameters.Expressions, out PascalFunctionType? functionType))
|
||||||
{
|
{
|
||||||
IsError = true;
|
if (functionType.ReturnType != PascalBasicType.Void)
|
||||||
logger?.LogError("The boolean type is expected.");
|
{
|
||||||
return;
|
factor.FactorType = functionType.ReturnType;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("The procedure '{}' returns void.", e.ProcedureName.IdentifierName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
factor.FactorType = PascalBasicType.Boolean;
|
factor.FactorType = PascalBasicType.Void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// factor -> not factor
|
||||||
|
factor.OnNotGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; };
|
||||||
|
|
||||||
// factor -> uminus factor
|
// factor -> uminus factor
|
||||||
factor.OnUminusGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; };
|
factor.OnUminusGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; };
|
||||||
|
|
||||||
|
// factor -> plus factor
|
||||||
|
factor.OnPlusGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostVisit(Term term)
|
public override void PostVisit(Term term)
|
||||||
|
@ -308,7 +287,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 多个ValueParameter下定义的参数列表
|
/// 多个ValueParameter下定义的参数列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly List<List<Symbol>> _valueParameters = [];
|
protected readonly List<List<Symbol>> ValueParameters = [];
|
||||||
|
|
||||||
public override void PreVisit(Subprogram subprogram)
|
public override void PreVisit(Subprogram subprogram)
|
||||||
{
|
{
|
||||||
|
@ -334,7 +313,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
base.PreVisit(subprogramHead);
|
base.PreVisit(subprogramHead);
|
||||||
|
|
||||||
_parameters = null;
|
_parameters = null;
|
||||||
_valueParameters.Clear();
|
ValueParameters.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostVisit(SubprogramHead subprogramHead)
|
public override void PostVisit(SubprogramHead subprogramHead)
|
||||||
|
@ -351,7 +330,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
|
|
||||||
// 正序遍历_valueParameter
|
// 正序遍历_valueParameter
|
||||||
// 倒序遍历其中的列表
|
// 倒序遍历其中的列表
|
||||||
foreach (List<Symbol> children in _valueParameters)
|
foreach (List<Symbol> children in ValueParameters)
|
||||||
{
|
{
|
||||||
foreach (Symbol symbol in children.AsEnumerable().Reverse())
|
foreach (Symbol symbol in children.AsEnumerable().Reverse())
|
||||||
{
|
{
|
||||||
|
@ -397,7 +376,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
|
|
||||||
valueParameter.IdentifierList.IsProcedure = true;
|
valueParameter.IdentifierList.IsProcedure = true;
|
||||||
_parameters = [];
|
_parameters = [];
|
||||||
_valueParameters.Add(_parameters);
|
ValueParameters.Add(_parameters);
|
||||||
if (valueParameter.IsReference)
|
if (valueParameter.IsReference)
|
||||||
{
|
{
|
||||||
valueParameter.IdentifierList.IsReference = true;
|
valueParameter.IdentifierList.IsReference = true;
|
||||||
|
@ -496,72 +475,22 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
public override void PostVisit(ProcedureCall procedureCall)
|
public override void PostVisit(ProcedureCall procedureCall)
|
||||||
{
|
{
|
||||||
base.PostVisit(procedureCall);
|
base.PostVisit(procedureCall);
|
||||||
// 查看当前符号表中procedureId是否注册
|
|
||||||
|
|
||||||
if (!SymbolTable.TryGetSymbol(procedureCall.ProcedureId.IdentifierName, out Symbol? procedure))
|
|
||||||
{
|
|
||||||
// id没有定义
|
|
||||||
IsError = true;
|
|
||||||
logger?.LogError("procedure '{}' is not defined.", procedureCall.ProcedureId.LiteralValue);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (procedure.SymbolType is not PascalFunctionType functionType)
|
|
||||||
{
|
|
||||||
// id不是函数类型,要找父符号表
|
|
||||||
if (!SymbolTable.TryGetParent(out SymbolTable? parent))
|
|
||||||
{
|
|
||||||
// 没找到父符号表,说明这个id是非函数变量
|
|
||||||
IsError = true;
|
|
||||||
logger?.LogError("Identifier '{}' is not a call-able.", procedureCall.ProcedureId.LiteralValue);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parent.TryGetSymbol(procedureCall.ProcedureId.IdentifierName, out Symbol? procedureParent))
|
|
||||||
{
|
|
||||||
// 找到父符号表但没有找到该id,说明这个id没定义
|
|
||||||
IsError = true;
|
|
||||||
logger?.LogError("procedure '{}' is not defined.", procedureCall.ProcedureId.LiteralValue);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 父符号表中找到该id
|
|
||||||
if (procedureParent.SymbolType is not PascalFunctionType functionTypeParent)
|
|
||||||
{
|
|
||||||
// 该符号不是函数类型
|
|
||||||
IsError = true;
|
|
||||||
logger?.LogError("Identifier '{}' is not a call-able.", procedureParent.SymbolName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 该符号是函数类型,赋给procedure
|
|
||||||
procedure = procedureParent;
|
|
||||||
functionType = functionTypeParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
procedureCall.OnParameterGenerator += (_, e) =>
|
procedureCall.OnParameterGenerator += (_, e) =>
|
||||||
{
|
{
|
||||||
// 检查procedure输入参数个数是否相符
|
if (ValidateProcedureCall(procedureCall.ProcedureId, e.Parameters.Expressions,
|
||||||
if (e.Parameters.Expressions.Count != functionType.Parameters.Count)
|
out PascalFunctionType? functionType))
|
||||||
{
|
{
|
||||||
IsError = true;
|
procedureCall.ReturnType = functionType.ReturnType;
|
||||||
logger?.LogError("Procedure '{}' expects {} parameters but {} provided.",
|
|
||||||
procedure.SymbolName,
|
|
||||||
functionType.Parameters.Count,
|
|
||||||
e.Parameters.Expressions.Count);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 检查每个参数的类型与procedure参数定义类型是否相符
|
procedureCall.OnNoParameterGenerator += (_, _) =>
|
||||||
foreach ((Expression expression, PascalParameterType parameterType) in e.Parameters.Expressions.Zip(
|
{
|
||||||
functionType.Parameters))
|
if (ValidateProcedureCall(procedureCall.ProcedureId, [],
|
||||||
|
out PascalFunctionType? functionType))
|
||||||
{
|
{
|
||||||
if (expression.ExpressionType != parameterType.ParameterType)
|
procedureCall.ReturnType = functionType.ReturnType;
|
||||||
{
|
|
||||||
IsError = true;
|
|
||||||
logger?.LogError("Parameter expect '{}' but '{}'",
|
|
||||||
parameterType.ParameterType.TypeName, expression.ExpressionType);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -569,10 +498,20 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
public override void PostVisit(Variable variable)
|
public override void PostVisit(Variable variable)
|
||||||
{
|
{
|
||||||
base.PostVisit(variable);
|
base.PostVisit(variable);
|
||||||
|
|
||||||
if (SymbolTable.TryGetSymbol(variable.Identifier.IdentifierName, out Symbol? id))
|
if (SymbolTable.TryGetSymbol(variable.Identifier.IdentifierName, out Symbol? id))
|
||||||
{
|
{
|
||||||
variable.VariableType = id.SymbolType;
|
variable.VariableType = id.SymbolType;
|
||||||
|
|
||||||
|
if (variable.VariableType is PascalFunctionType functionType)
|
||||||
|
{
|
||||||
|
// 考虑不带参数的函数调用
|
||||||
|
if (functionType.Parameters.Count == 0 && functionType.ReturnType != PascalBasicType.Void)
|
||||||
|
{
|
||||||
|
variable.VariableType = functionType.ReturnType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < variable.VarPart.IndexCount; i++)
|
for (int i = 0; i < variable.VarPart.IndexCount; i++)
|
||||||
{
|
{
|
||||||
if (variable.VariableType is PascalArrayType arrayType)
|
if (variable.VariableType is PascalArrayType arrayType)
|
||||||
|
@ -614,4 +553,90 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
identifierVarPart.IndexCount = e.IndexParameters.Expressions.Count;
|
identifierVarPart.IndexCount = e.IndexParameters.Expressions.Count;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly HashSet<string> s_pascalCoreProcedures =
|
||||||
|
[
|
||||||
|
"read",
|
||||||
|
"readln",
|
||||||
|
"write",
|
||||||
|
"writeln"
|
||||||
|
];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证过程调用的类型正确性
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="procedureName">过程的名称</param>
|
||||||
|
/// <param name="parameters">调用过程的参数</param>
|
||||||
|
/// <param name="functionType">过程的类型</param>
|
||||||
|
/// <returns>是否正确进行调用</returns>
|
||||||
|
private bool ValidateProcedureCall(IdentifierSemanticToken procedureName, List<Expression> parameters,
|
||||||
|
[NotNullWhen(true)] out PascalFunctionType? functionType)
|
||||||
|
{
|
||||||
|
if (s_pascalCoreProcedures.Contains(procedureName.IdentifierName))
|
||||||
|
{
|
||||||
|
functionType = PascalFunctionType.CoreFuntionType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SymbolTable.TryGetSymbol(procedureName.IdentifierName, out Symbol? symbol))
|
||||||
|
{
|
||||||
|
functionType = null;
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Identifier '{}' is not defined.", procedureName.IdentifierName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PascalFunctionType? targetFunctionType = null;
|
||||||
|
if (symbol.SymbolType is not PascalFunctionType pascalFunctionType)
|
||||||
|
{
|
||||||
|
// 尝试查询父级符号表
|
||||||
|
// 处理过程定义中的递归调用问题
|
||||||
|
if (SymbolTable.TryGetParent(out SymbolTable? parent))
|
||||||
|
{
|
||||||
|
if (parent.TryGetSymbol(procedureName.IdentifierName, out Symbol? parentSymbol))
|
||||||
|
{
|
||||||
|
if (parentSymbol.SymbolType is PascalFunctionType parentFunctionType)
|
||||||
|
{
|
||||||
|
targetFunctionType = parentFunctionType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetFunctionType = pascalFunctionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetFunctionType is null)
|
||||||
|
{
|
||||||
|
functionType = null;
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Identifier '{}' is not call-able.", procedureName.IdentifierName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetFunctionType.Parameters.Count != parameters.Count)
|
||||||
|
{
|
||||||
|
functionType = null;
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Procedure '{}' needs {} parameters but provide {} parameters.",
|
||||||
|
procedureName.IdentifierName,
|
||||||
|
targetFunctionType.Parameters.Count, parameters.Count);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ((Expression expression, PascalParameterType parameterType) in parameters.Zip(targetFunctionType
|
||||||
|
.Parameters))
|
||||||
|
{
|
||||||
|
if (expression.ExpressionType != parameterType.ParameterType)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Parameter expect '{}' but '{}' is provided.",
|
||||||
|
parameterType.ParameterType, expression.ExpressionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
functionType = targetFunctionType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,28 +38,6 @@ public class BasicType : NonTerminatedSyntaxNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void GenerateCCode(CCodeBuilder builder)
|
|
||||||
{
|
|
||||||
var keywordType = Children[0].Convert<TerminatedSyntaxNode>().Token
|
|
||||||
.Convert<KeywordSemanticToken>().KeywordType;
|
|
||||||
|
|
||||||
switch (keywordType)
|
|
||||||
{
|
|
||||||
case KeywordType.Integer:
|
|
||||||
builder.AddString(" int");
|
|
||||||
break;
|
|
||||||
case KeywordType.Real:
|
|
||||||
builder.AddString(" double");
|
|
||||||
break;
|
|
||||||
case KeywordType.Boolean:
|
|
||||||
builder.AddString(" bool");
|
|
||||||
break;
|
|
||||||
case KeywordType.Character:
|
|
||||||
builder.AddString(" char");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
|
|
@ -6,12 +6,12 @@ using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnSimpleExpressionGeneratorEventArgs : EventArgs
|
public class SimpleExpressionGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required SimpleExpression SimpleExpression { get; init; }
|
public required SimpleExpression SimpleExpression { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnRelationGeneratorEventArgs : EventArgs
|
public class RelationGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required SimpleExpression Left { get; init; }
|
public required SimpleExpression Left { get; init; }
|
||||||
|
|
||||||
|
@ -76,12 +76,12 @@ public class Expression : NonTerminatedSyntaxNode
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 直接赋值产生式的事件
|
/// 直接赋值产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnSimpleExpressionGeneratorEventArgs>? OnSimpleExpressionGenerator;
|
public event EventHandler<SimpleExpressionGeneratorEventArgs>? OnSimpleExpressionGenerator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 关系产生式的事件
|
/// 关系产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnRelationGeneratorEventArgs>? OnRelationGenerator;
|
public event EventHandler<RelationGeneratorEventArgs>? OnRelationGenerator;
|
||||||
|
|
||||||
private PascalType? _expressionType;
|
private PascalType? _expressionType;
|
||||||
|
|
||||||
|
@ -111,14 +111,14 @@ public class Expression : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
if (Children.Count == 1)
|
if (Children.Count == 1)
|
||||||
{
|
{
|
||||||
OnSimpleExpressionGenerator?.Invoke(this, new OnSimpleExpressionGeneratorEventArgs
|
OnSimpleExpressionGenerator?.Invoke(this, new SimpleExpressionGeneratorEventArgs
|
||||||
{
|
{
|
||||||
SimpleExpression = Children[0].Convert<SimpleExpression>()
|
SimpleExpression = Children[0].Convert<SimpleExpression>()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnRelationGenerator?.Invoke(this, new OnRelationGeneratorEventArgs
|
OnRelationGenerator?.Invoke(this, new RelationGeneratorEventArgs
|
||||||
{
|
{
|
||||||
Left = Children[0].Convert<SimpleExpression>(),
|
Left = Children[0].Convert<SimpleExpression>(),
|
||||||
Operator = Children[1].Convert<RelationOperator>(),
|
Operator = Children[1].Convert<RelationOperator>(),
|
||||||
|
|
|
@ -1,43 +1,57 @@
|
||||||
using Canon.Core.Abstractions;
|
using Canon.Core.Abstractions;
|
||||||
using Canon.Core.CodeGenerators;
|
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
using Canon.Core.SemanticParser;
|
using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnNumberGeneratorEventArgs : EventArgs
|
public class NumberGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required NumberSemanticToken Token { get; init; }
|
public required NumberSemanticToken Token { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnVariableGeneratorEventArgs : EventArgs
|
public class VariableGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required Variable Variable { get; init; }
|
public required Variable Variable { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnParethnesisGeneratorEventArgs : EventArgs
|
public class ParethnesisGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required Expression Expression { get; init; }
|
public required Expression Expression { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnProcedureCallGeneratorEventArgs : EventArgs
|
public class NoParameterProcedureCallGeneratorEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public required IdentifierSemanticToken ProcedureName { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProcedureCallGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required IdentifierSemanticToken ProcedureName { get; init; }
|
public required IdentifierSemanticToken ProcedureName { get; init; }
|
||||||
|
|
||||||
public required ExpressionList Parameters { get; init; }
|
public required ExpressionList Parameters { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnNotGeneratorEventArgs : EventArgs
|
public class NotGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required Factor Factor { get; init; }
|
public required Factor Factor { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnUminusGeneratorEventArgs : EventArgs
|
public class UminusGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required Factor Factor { get; init; }
|
public required Factor Factor { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PlusGeneratorEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public required Factor Factor { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BooleanGeneratorEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public required bool Value { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Factor : NonTerminatedSyntaxNode
|
public class Factor : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.Factor;
|
public override NonTerminatorType Type => NonTerminatorType.Factor;
|
||||||
|
@ -57,32 +71,47 @@ public class Factor : NonTerminatedSyntaxNode
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用数值产生式的事件
|
/// 使用数值产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnNumberGeneratorEventArgs>? OnNumberGenerator;
|
public event EventHandler<NumberGeneratorEventArgs>? OnNumberGenerator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用括号产生式的事件
|
/// 使用括号产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnParethnesisGeneratorEventArgs>? OnParethnesisGenerator;
|
public event EventHandler<ParethnesisGeneratorEventArgs>? OnParethnesisGenerator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用变量产生式的事件
|
/// 使用变量产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnVariableGeneratorEventArgs>? OnVariableGenerator;
|
public event EventHandler<VariableGeneratorEventArgs>? OnVariableGenerator;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 使用过程调用产生式的事件
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<OnProcedureCallGeneratorEventArgs>? OnProcedureCallGenerator;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用否定产生式的事件
|
/// 使用否定产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnNotGeneratorEventArgs>? OnNotGenerator;
|
public event EventHandler<NotGeneratorEventArgs>? OnNotGenerator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用负号产生式的事件
|
/// 使用负号产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnUminusGeneratorEventArgs>? OnUminusGenerator;
|
public event EventHandler<UminusGeneratorEventArgs>? OnUminusGenerator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用加号产生式的事件
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<PlusGeneratorEventArgs>? OnPlusGenerator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用布尔值产生式的事件
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<BooleanGeneratorEventArgs>? OnBooleanGenerator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 没有参数的过程调用产生式事件
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<NoParameterProcedureCallGeneratorEventArgs>? OnNoParameterProcedureCallGenerator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 过程调用产生式的事件
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<ProcedureCallGeneratorEventArgs>? OnProcedureCallGenerator;
|
||||||
|
|
||||||
private PascalType? _factorType;
|
private PascalType? _factorType;
|
||||||
|
|
||||||
|
@ -97,10 +126,7 @@ public class Factor : NonTerminatedSyntaxNode
|
||||||
|
|
||||||
return _factorType;
|
return _factorType;
|
||||||
}
|
}
|
||||||
set
|
set { _factorType = value; }
|
||||||
{
|
|
||||||
_factorType = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Factor Create(List<SyntaxNodeBase> children)
|
public static Factor Create(List<SyntaxNodeBase> children)
|
||||||
|
@ -112,51 +138,94 @@ public class Factor : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
if (Children.Count == 1)
|
if (Children.Count == 1)
|
||||||
{
|
{
|
||||||
//factor -> num
|
|
||||||
if (Children[0].IsTerminated)
|
if (Children[0].IsTerminated)
|
||||||
{
|
{
|
||||||
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
|
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||||
OnNumberGenerator?.Invoke(this,
|
|
||||||
new OnNumberGeneratorEventArgs { Token = token.Convert<NumberSemanticToken>() });
|
switch (token.TokenType)
|
||||||
|
{
|
||||||
|
// factor -> num
|
||||||
|
case SemanticTokenType.Number:
|
||||||
|
OnNumberGenerator?.Invoke(this,
|
||||||
|
new NumberGeneratorEventArgs { Token = token.Convert<NumberSemanticToken>() });
|
||||||
|
break;
|
||||||
|
// factor -> true | false
|
||||||
|
case SemanticTokenType.Keyword:
|
||||||
|
KeywordSemanticToken keywordSemanticToken = token.Convert<KeywordSemanticToken>();
|
||||||
|
|
||||||
|
switch (keywordSemanticToken.KeywordType)
|
||||||
|
{
|
||||||
|
case KeywordType.True:
|
||||||
|
OnBooleanGenerator?.Invoke(this, new BooleanGeneratorEventArgs { Value = true });
|
||||||
|
break;
|
||||||
|
case KeywordType.False:
|
||||||
|
OnBooleanGenerator?.Invoke(this, new BooleanGeneratorEventArgs { Value = false });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// factor -> variable
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnVariableGenerator?.Invoke(this,
|
OnVariableGenerator?.Invoke(this,
|
||||||
new OnVariableGeneratorEventArgs { Variable = Children[0].Convert<Variable>() });
|
new VariableGeneratorEventArgs { Variable = Children[0].Convert<Variable>() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//factor -> ( expression )
|
|
||||||
else if (Children.Count == 3)
|
else if (Children.Count == 3)
|
||||||
{
|
{
|
||||||
OnParethnesisGenerator?.Invoke(this,
|
TerminatedSyntaxNode terminatedSyntaxNode = Children[0].Convert<TerminatedSyntaxNode>();
|
||||||
new OnParethnesisGeneratorEventArgs { Expression = Children[1].Convert<Expression>() });
|
|
||||||
|
// factor -> ( expression )
|
||||||
|
if (terminatedSyntaxNode.Token.TokenType == SemanticTokenType.Delimiter)
|
||||||
|
{
|
||||||
|
OnParethnesisGenerator?.Invoke(this,
|
||||||
|
new ParethnesisGeneratorEventArgs { Expression = Children[1].Convert<Expression>() });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// factor -> id ( )
|
||||||
|
OnNoParameterProcedureCallGenerator?.Invoke(this, new NoParameterProcedureCallGeneratorEventArgs
|
||||||
|
{
|
||||||
|
ProcedureName = terminatedSyntaxNode.Token.Convert<IdentifierSemanticToken>()
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//factor -> id ( expression )
|
|
||||||
else if (Children.Count == 4)
|
else if (Children.Count == 4)
|
||||||
{
|
{
|
||||||
OnProcedureCallGenerator?.Invoke(this,
|
// factor -> id ( expressionList)
|
||||||
new OnProcedureCallGeneratorEventArgs
|
OnProcedureCallGenerator?.Invoke(this, new ProcedureCallGeneratorEventArgs
|
||||||
{
|
{
|
||||||
ProcedureName =
|
ProcedureName = Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||||
Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
Parameters = Children[2].Convert<ExpressionList>()
|
||||||
Parameters = Children[2].Convert<ExpressionList>()
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
|
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||||
Factor factor = Children[1].Convert<Factor>();
|
Factor factor = Children[1].Convert<Factor>();
|
||||||
|
|
||||||
if (token.TokenType == SemanticTokenType.Keyword)
|
if (token.TokenType == SemanticTokenType.Keyword)
|
||||||
{
|
{
|
||||||
// factor -> not factor
|
// factor -> not factor
|
||||||
OnNotGenerator?.Invoke(this, new OnNotGeneratorEventArgs { Factor = factor });
|
OnNotGenerator?.Invoke(this, new NotGeneratorEventArgs { Factor = factor });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// factor -> uminus factor
|
OperatorSemanticToken operatorSemanticToken = token.Convert<OperatorSemanticToken>();
|
||||||
OnUminusGenerator?.Invoke(this, new OnUminusGeneratorEventArgs { Factor = factor });
|
|
||||||
|
switch (operatorSemanticToken.OperatorType)
|
||||||
|
{
|
||||||
|
// factor -> + factor
|
||||||
|
case OperatorType.Plus:
|
||||||
|
OnPlusGenerator?.Invoke(this, new PlusGeneratorEventArgs { Factor = factor });
|
||||||
|
break;
|
||||||
|
// factor -> - factor
|
||||||
|
case OperatorType.Minus:
|
||||||
|
OnUminusGenerator?.Invoke(this, new UminusGeneratorEventArgs { Factor = factor });
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,14 @@ using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnIdentifierGeneratorEventArgs : EventArgs
|
public class IdentifierGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required IdentifierSemanticToken IdentifierToken { get; init; }
|
public required IdentifierSemanticToken IdentifierToken { get; init; }
|
||||||
|
|
||||||
public required IdentifierList IdentifierList { get; init; }
|
public required IdentifierList IdentifierList { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnTypeGeneratorEventArgs : EventArgs
|
public class TypeGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required TypeSyntaxNode TypeSyntaxNode { get; init; }
|
public required TypeSyntaxNode TypeSyntaxNode { get; init; }
|
||||||
}
|
}
|
||||||
|
@ -66,9 +66,9 @@ public class IdentifierList : NonTerminatedSyntaxNode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsProcedure { get; set; }
|
public bool IsProcedure { get; set; }
|
||||||
|
|
||||||
public event EventHandler<OnIdentifierGeneratorEventArgs>? OnIdentifierGenerator;
|
public event EventHandler<IdentifierGeneratorEventArgs>? OnIdentifierGenerator;
|
||||||
|
|
||||||
public event EventHandler<OnTypeGeneratorEventArgs>? OnTypeGenerator;
|
public event EventHandler<TypeGeneratorEventArgs>? OnTypeGenerator;
|
||||||
|
|
||||||
public static IdentifierList Create(List<SyntaxNodeBase> children)
|
public static IdentifierList Create(List<SyntaxNodeBase> children)
|
||||||
{
|
{
|
||||||
|
@ -80,11 +80,11 @@ public class IdentifierList : NonTerminatedSyntaxNode
|
||||||
if (Children.Count == 2)
|
if (Children.Count == 2)
|
||||||
{
|
{
|
||||||
OnTypeGenerator?.Invoke(this,
|
OnTypeGenerator?.Invoke(this,
|
||||||
new OnTypeGeneratorEventArgs { TypeSyntaxNode = Children[1].Convert<TypeSyntaxNode>() });
|
new TypeGeneratorEventArgs { TypeSyntaxNode = Children[1].Convert<TypeSyntaxNode>() });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnIdentifierGenerator?.Invoke(this, new OnIdentifierGeneratorEventArgs
|
OnIdentifierGenerator?.Invoke(this, new IdentifierGeneratorEventArgs
|
||||||
{
|
{
|
||||||
IdentifierToken = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
IdentifierToken = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||||
IdentifierList = Children[2].Convert<IdentifierList>()
|
IdentifierList = Children[2].Convert<IdentifierList>()
|
||||||
|
|
|
@ -4,7 +4,7 @@ using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnIndexGeneratorEventArgs : EventArgs
|
public class IndexGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required ExpressionList IndexParameters { get; init; }
|
public required ExpressionList IndexParameters { get; init; }
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用了索引产生式的事件
|
/// 使用了索引产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnIndexGeneratorEventArgs>? OnIndexGenerator;
|
public event EventHandler<IndexGeneratorEventArgs>? OnIndexGenerator;
|
||||||
|
|
||||||
public static IdentifierVarPart Create(List<SyntaxNodeBase> children)
|
public static IdentifierVarPart Create(List<SyntaxNodeBase> children)
|
||||||
{
|
{
|
||||||
|
@ -49,7 +49,7 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
if (Children.Count == 3)
|
if (Children.Count == 3)
|
||||||
{
|
{
|
||||||
OnIndexGenerator?.Invoke(this, new OnIndexGeneratorEventArgs()
|
OnIndexGenerator?.Invoke(this, new IndexGeneratorEventArgs()
|
||||||
{
|
{
|
||||||
IndexParameters = Children[1].Convert<ExpressionList>()
|
IndexParameters = Children[1].Convert<ExpressionList>()
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
using Canon.Core.Abstractions;
|
using Canon.Core.Abstractions;
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnParameterGeneratorEventArgs : EventArgs
|
public class ParameterGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required ExpressionList Parameters { get; init; }
|
public required ExpressionList Parameters { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NoParameterGeneratorEventArgs : EventArgs;
|
||||||
|
|
||||||
public class ProcedureCall : NonTerminatedSyntaxNode
|
public class ProcedureCall : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.ProcedureCall;
|
public override NonTerminatorType Type => NonTerminatorType.ProcedureCall;
|
||||||
|
@ -19,7 +22,31 @@ public class ProcedureCall : NonTerminatedSyntaxNode
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 调用函数时含有参数的事件
|
/// 调用函数时含有参数的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnParameterGeneratorEventArgs>? OnParameterGenerator;
|
public event EventHandler<ParameterGeneratorEventArgs>? OnParameterGenerator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 调用函数是没有参数的事件
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<NoParameterGeneratorEventArgs>? OnNoParameterGenerator;
|
||||||
|
|
||||||
|
private PascalType? _pascalType;
|
||||||
|
|
||||||
|
public PascalType ReturnType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_pascalType is null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _pascalType;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_pascalType = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
|
@ -42,12 +69,17 @@ public class ProcedureCall : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
if (Children.Count == 4)
|
if (Children.Count == 4)
|
||||||
{
|
{
|
||||||
OnParameterGenerator?.Invoke(this, new OnParameterGeneratorEventArgs
|
OnParameterGenerator?.Invoke(this, new ParameterGeneratorEventArgs
|
||||||
{
|
{
|
||||||
Parameters = Children[2].Convert<ExpressionList>()
|
Parameters = Children[2].Convert<ExpressionList>()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OnNoParameterGenerator?.Invoke(this, new NoParameterGeneratorEventArgs());
|
||||||
|
}
|
||||||
|
|
||||||
OnParameterGenerator = null;
|
OnParameterGenerator = null;
|
||||||
|
OnNoParameterGenerator = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,12 @@ using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnTermGeneratorEventArgs : EventArgs
|
public class TermGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required Term Term { get; init; }
|
public required Term Term { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnAddGeneratorEventArgs : EventArgs
|
public class AddGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required SimpleExpression Left { get; init; }
|
public required SimpleExpression Left { get; init; }
|
||||||
|
|
||||||
|
@ -38,12 +38,12 @@ public class SimpleExpression : NonTerminatedSyntaxNode
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 直接赋值产生式的事件
|
/// 直接赋值产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnTermGeneratorEventArgs>? OnTermGenerator;
|
public event EventHandler<TermGeneratorEventArgs>? OnTermGenerator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加法产生式的事件
|
/// 加法产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnAddGeneratorEventArgs>? OnAddGenerator;
|
public event EventHandler<AddGeneratorEventArgs>? OnAddGenerator;
|
||||||
|
|
||||||
private PascalType? _simpleExpressionType;
|
private PascalType? _simpleExpressionType;
|
||||||
|
|
||||||
|
@ -73,14 +73,14 @@ public class SimpleExpression : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
if (Children.Count == 1)
|
if (Children.Count == 1)
|
||||||
{
|
{
|
||||||
OnTermGenerator?.Invoke(this, new OnTermGeneratorEventArgs
|
OnTermGenerator?.Invoke(this, new TermGeneratorEventArgs
|
||||||
{
|
{
|
||||||
Term = Children[0].Convert<Term>()
|
Term = Children[0].Convert<Term>()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnAddGenerator?.Invoke(this, new OnAddGeneratorEventArgs
|
OnAddGenerator?.Invoke(this, new AddGeneratorEventArgs
|
||||||
{
|
{
|
||||||
Left = Children[0].Convert<SimpleExpression>(),
|
Left = Children[0].Convert<SimpleExpression>(),
|
||||||
Operator = Children[1].Convert<AddOperator>(),
|
Operator = Children[1].Convert<AddOperator>(),
|
||||||
|
|
|
@ -5,21 +5,14 @@ using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnAssignGeneratorEventArgs : EventArgs
|
public class AssignGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required Variable Variable { get; init; }
|
public required Variable Variable { get; init; }
|
||||||
|
|
||||||
public required Expression Expression { get; init; }
|
public required Expression Expression { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnReturnGeneratorEventArgs : EventArgs
|
public class IfGeneratorEventArgs : EventArgs
|
||||||
{
|
|
||||||
public required IdentifierSemanticToken FunctionName { get; set; }
|
|
||||||
|
|
||||||
public required Expression Expression { get; init; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OnIfGeneratorEventArgs : EventArgs
|
|
||||||
{
|
{
|
||||||
public required Expression Condition { get; init; }
|
public required Expression Condition { get; init; }
|
||||||
|
|
||||||
|
@ -28,7 +21,7 @@ public class OnIfGeneratorEventArgs : EventArgs
|
||||||
public required ElsePart ElseSentence { get; init; }
|
public required ElsePart ElseSentence { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnForGeneratorEventArgs : EventArgs
|
public class ForGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required IdentifierSemanticToken Iterator { get; init; }
|
public required IdentifierSemanticToken Iterator { get; init; }
|
||||||
|
|
||||||
|
@ -58,22 +51,17 @@ public class Statement : NonTerminatedSyntaxNode
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用赋值产生式的事件
|
/// 使用赋值产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnAssignGeneratorEventArgs>? OnAssignGenerator;
|
public event EventHandler<AssignGeneratorEventArgs>? OnAssignGenerator;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 使用返回产生式的事件
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<OnReturnGeneratorEventArgs>? OnReturnGenerator;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用If产生式的事件
|
/// 使用If产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnIfGeneratorEventArgs>? OnIfGenerator;
|
public event EventHandler<IfGeneratorEventArgs>? OnIfGenerator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用For产生式的事件
|
/// 使用For产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnForGeneratorEventArgs>? OnForGenerator;
|
public event EventHandler<ForGeneratorEventArgs>? OnForGenerator;
|
||||||
|
|
||||||
public static Statement Create(List<SyntaxNodeBase> children)
|
public static Statement Create(List<SyntaxNodeBase> children)
|
||||||
{
|
{
|
||||||
|
@ -84,41 +72,32 @@ public class Statement : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
if (Children.Count == 3)
|
if (Children.Count == 3)
|
||||||
{
|
{
|
||||||
if (Children[0].IsTerminated)
|
OnAssignGenerator?.Invoke(this,
|
||||||
{
|
new AssignGeneratorEventArgs
|
||||||
OnReturnGenerator?.Invoke(this, new OnReturnGeneratorEventArgs
|
|
||||||
{
|
{
|
||||||
FunctionName = Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
Variable = Children[0].Convert<Variable>(), Expression = Children[2].Convert<Expression>()
|
||||||
Expression = Children[2].Convert<Expression>()
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OnAssignGenerator?.Invoke(this, new OnAssignGeneratorEventArgs
|
|
||||||
{
|
|
||||||
Variable = Children[0].Convert<Variable>(),
|
|
||||||
Expression = Children[2].Convert<Expression>()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (Children.Count == 5)
|
else if (Children.Count == 5)
|
||||||
{
|
{
|
||||||
OnIfGenerator?.Invoke(this, new OnIfGeneratorEventArgs
|
OnIfGenerator?.Invoke(this,
|
||||||
{
|
new IfGeneratorEventArgs
|
||||||
Condition = Children[1].Convert<Expression>(),
|
{
|
||||||
Sentence = Children[3].Convert<Statement>(),
|
Condition = Children[1].Convert<Expression>(),
|
||||||
ElseSentence = Children[4].Convert<ElsePart>()
|
Sentence = Children[3].Convert<Statement>(),
|
||||||
});
|
ElseSentence = Children[4].Convert<ElsePart>()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else if (Children.Count == 8)
|
else if (Children.Count == 8)
|
||||||
{
|
{
|
||||||
OnForGenerator?.Invoke(this, new OnForGeneratorEventArgs
|
OnForGenerator?.Invoke(this,
|
||||||
{
|
new ForGeneratorEventArgs
|
||||||
Iterator = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
{
|
||||||
Begin = Children[3].Convert<Expression>(),
|
Iterator = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||||
End = Children[5].Convert<Expression>(),
|
Begin = Children[3].Convert<Expression>(),
|
||||||
Sentence = Children[7].Convert<Statement>()
|
End = Children[5].Convert<Expression>(),
|
||||||
});
|
Sentence = Children[7].Convert<Statement>()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnProcedureGeneratorEventArgs : EventArgs;
|
public class ProcedureGeneratorEventArgs : EventArgs;
|
||||||
|
|
||||||
public class OnFunctionGeneratorEventArgs : EventArgs
|
public class FunctionGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required BasicType ReturnType { get; init; }
|
public required BasicType ReturnType { get; init; }
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,9 @@ public class SubprogramHead : NonTerminatedSyntaxNode
|
||||||
RaiseEvent();
|
RaiseEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public event EventHandler<OnProcedureGeneratorEventArgs>? OnProcedureGenerator;
|
public event EventHandler<ProcedureGeneratorEventArgs>? OnProcedureGenerator;
|
||||||
|
|
||||||
public event EventHandler<OnFunctionGeneratorEventArgs>? OnFunctionGenerator;
|
public event EventHandler<FunctionGeneratorEventArgs>? OnFunctionGenerator;
|
||||||
|
|
||||||
public static SubprogramHead Create(List<SyntaxNodeBase> children)
|
public static SubprogramHead Create(List<SyntaxNodeBase> children)
|
||||||
{
|
{
|
||||||
|
@ -71,12 +71,12 @@ public class SubprogramHead : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
if (IsProcedure)
|
if (IsProcedure)
|
||||||
{
|
{
|
||||||
OnProcedureGenerator?.Invoke(this, new OnProcedureGeneratorEventArgs());
|
OnProcedureGenerator?.Invoke(this, new ProcedureGeneratorEventArgs());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnFunctionGenerator?.Invoke(this,
|
OnFunctionGenerator?.Invoke(this,
|
||||||
new OnFunctionGeneratorEventArgs { ReturnType = Children[4].Convert<BasicType>() });
|
new FunctionGeneratorEventArgs { ReturnType = Children[4].Convert<BasicType>() });
|
||||||
}
|
}
|
||||||
|
|
||||||
OnProcedureGenerator = null;
|
OnProcedureGenerator = null;
|
||||||
|
|
|
@ -5,7 +5,7 @@ using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public abstract class SyntaxNodeBase : ICCodeGenerator
|
public abstract class SyntaxNodeBase
|
||||||
{
|
{
|
||||||
public abstract bool IsTerminated { get; }
|
public abstract bool IsTerminated { get; }
|
||||||
|
|
||||||
|
@ -25,13 +25,6 @@ public abstract class SyntaxNodeBase : ICCodeGenerator
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 语法树节点基类对于生成C代码的默认实现
|
|
||||||
/// </summary>
|
|
||||||
public virtual void GenerateCCode(CCodeBuilder builder)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return IsTerminated.ToString();
|
return IsTerminated.ToString();
|
||||||
|
|
|
@ -5,12 +5,12 @@ using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnFactorGeneratorEventArgs : EventArgs
|
public class FactorGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required Factor Factor { get; init; }
|
public required Factor Factor { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnMultiplyGeneratorEventArgs : EventArgs
|
public class MultiplyGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required Term Left { get; init; }
|
public required Term Left { get; init; }
|
||||||
|
|
||||||
|
@ -38,12 +38,12 @@ public class Term : NonTerminatedSyntaxNode
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 直接赋值产生式的事件
|
/// 直接赋值产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnFactorGeneratorEventArgs>? OnFactorGenerator;
|
public event EventHandler<FactorGeneratorEventArgs>? OnFactorGenerator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 乘法产生式的事件
|
/// 乘法产生式的事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<OnMultiplyGeneratorEventArgs>? OnMultiplyGenerator;
|
public event EventHandler<MultiplyGeneratorEventArgs>? OnMultiplyGenerator;
|
||||||
|
|
||||||
private PascalType? _termType;
|
private PascalType? _termType;
|
||||||
|
|
||||||
|
@ -73,14 +73,14 @@ public class Term : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
if (Children.Count == 1)
|
if (Children.Count == 1)
|
||||||
{
|
{
|
||||||
OnFactorGenerator?.Invoke(this, new OnFactorGeneratorEventArgs
|
OnFactorGenerator?.Invoke(this, new FactorGeneratorEventArgs
|
||||||
{
|
{
|
||||||
Factor = Children[0].Convert<Factor>()
|
Factor = Children[0].Convert<Factor>()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnMultiplyGenerator?.Invoke(this, new OnMultiplyGeneratorEventArgs
|
OnMultiplyGenerator?.Invoke(this, new MultiplyGeneratorEventArgs
|
||||||
{
|
{
|
||||||
Left = Children[0].Convert<Term>(),
|
Left = Children[0].Convert<Term>(),
|
||||||
Operator = Children[1].Convert<MultiplyOperator>(),
|
Operator = Children[1].Convert<MultiplyOperator>(),
|
||||||
|
|
|
@ -5,12 +5,12 @@ using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnBasicTypeGeneratorEventArgs : EventArgs
|
public class BasicTypeGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required BasicType BasicType { get; init; }
|
public required BasicType BasicType { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnArrayTypeGeneratorEventArgs : EventArgs
|
public class ArrayTypeGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required Period Period { get; init; }
|
public required Period Period { get; init; }
|
||||||
|
|
||||||
|
@ -33,9 +33,9 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
|
||||||
RaiseEvent();
|
RaiseEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public event EventHandler<OnBasicTypeGeneratorEventArgs>? OnBasicTypeGenerator;
|
public event EventHandler<BasicTypeGeneratorEventArgs>? OnBasicTypeGenerator;
|
||||||
|
|
||||||
public event EventHandler<OnArrayTypeGeneratorEventArgs>? OnArrayTypeGenerator;
|
public event EventHandler<ArrayTypeGeneratorEventArgs>? OnArrayTypeGenerator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否在过程定义中使用
|
/// 是否在过程定义中使用
|
||||||
|
@ -74,14 +74,14 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
if (Children.Count == 1)
|
if (Children.Count == 1)
|
||||||
{
|
{
|
||||||
OnBasicTypeGenerator?.Invoke(this, new OnBasicTypeGeneratorEventArgs
|
OnBasicTypeGenerator?.Invoke(this, new BasicTypeGeneratorEventArgs
|
||||||
{
|
{
|
||||||
BasicType = Children[0].Convert<BasicType>()
|
BasicType = Children[0].Convert<BasicType>()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnArrayTypeGenerator?.Invoke(this, new OnArrayTypeGeneratorEventArgs
|
OnArrayTypeGenerator?.Invoke(this, new ArrayTypeGeneratorEventArgs
|
||||||
{
|
{
|
||||||
Period = Children[2].Convert<Period>(),
|
Period = Children[2].Convert<Period>(),
|
||||||
BasicType = Children[5].Convert<BasicType>()
|
BasicType = Children[5].Convert<BasicType>()
|
||||||
|
|
|
@ -30,6 +30,7 @@ public class BasicTest
|
||||||
|
|
||||||
string result = visitor.Builder.Build();
|
string result = visitor.Builder.Build();
|
||||||
_output.WriteLine(result);
|
_output.WriteLine(result);
|
||||||
Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nint main()\n{\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
|
Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nint main()\n{\n;\n\nreturn 0;\n}\n",
|
||||||
|
visitor.Builder.Build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,13 +72,37 @@ public class SubprogramTests
|
||||||
|
|
||||||
string result = visitor.Builder.Build();
|
string result = visitor.Builder.Build();
|
||||||
_output.WriteLine(result);
|
_output.WriteLine(result);
|
||||||
Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nbool b, a;" +
|
Assert.Equal("""
|
||||||
"\nint func1(int* a, int b, double c)\n{\nint func1;\n" +
|
#include <stdbool.h>
|
||||||
"{\n(*a) = b + c;\nfunc1 = (*a) * 3;\n;\n}\nreturn func1;\n}\n" +
|
#include <stdio.h>
|
||||||
"char func2(bool* a, bool* b, char c[][6])\n{\nchar func2;\n" +
|
bool b, a;
|
||||||
"{\n(*a) = (*b) && (!(*b));\nfunc2 = c[5-0][8-3];\n;\n}\nreturn func2;\n}" +
|
int func1(int* a, int b, double c)
|
||||||
"\nint main()\n{\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
|
{
|
||||||
|
int func1;
|
||||||
|
{
|
||||||
|
(*a) = b + c;
|
||||||
|
func1 = (*a) * 3;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return func1;
|
||||||
|
}
|
||||||
|
char func2(bool* a, bool* b, char c[][6])
|
||||||
|
{
|
||||||
|
char func2;
|
||||||
|
{
|
||||||
|
(*a) = (*b) && (~(*b));
|
||||||
|
func2 = c[5-0][8-3];
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return func2;
|
||||||
|
}
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
""", visitor.Builder.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@ public class PascalGrammarTests
|
||||||
public void DoNothingTest()
|
public void DoNothingTest()
|
||||||
{
|
{
|
||||||
const string program = """
|
const string program = """
|
||||||
program DoNothing;
|
program DoNothing;
|
||||||
begin
|
begin
|
||||||
end.
|
end.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||||
Assert.Equal("DoNothing", root.Head.ProgramName.LiteralValue);
|
Assert.Equal("DoNothing", root.Head.ProgramName.LiteralValue);
|
||||||
|
@ -161,4 +161,86 @@ public class PascalGrammarTests
|
||||||
|
|
||||||
CompilerHelpers.Analyse(program);
|
CompilerHelpers.Analyse(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ProcedureCallTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var a : integer;
|
||||||
|
function test : integer;
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
test;
|
||||||
|
a := test;
|
||||||
|
test();
|
||||||
|
a := test();
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
CompilerHelpers.Analyse(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ProcedureDefinitionTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
procedure test();
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
test();
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
CompilerHelpers.Analyse(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FactorTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var a : integer;
|
||||||
|
begin
|
||||||
|
a := 1 + +1;
|
||||||
|
a := 1 - -1;
|
||||||
|
a := 1 + -1;
|
||||||
|
a := 1 - +1;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
CompilerHelpers.Analyse(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TrueFalseTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
const a = true; b = false;
|
||||||
|
var c, d : boolean;
|
||||||
|
begin
|
||||||
|
c := true;
|
||||||
|
d := false;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
CompilerHelpers.Analyse(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ProcedureAndVariableTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
begin
|
||||||
|
test
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
CompilerHelpers.Analyse(program);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using Canon.Core.Abstractions;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Exceptions;
|
||||||
using Canon.Core.GrammarParser;
|
using Canon.Core.GrammarParser;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
@ -159,11 +159,6 @@ public class SimpleGrammarWithEmptyTests(ITestOutputHelper testOutputHelper)
|
||||||
};
|
};
|
||||||
|
|
||||||
Grammar grammar = builder.Build();
|
Grammar grammar = builder.Build();
|
||||||
IGrammarParser parser = grammar.ToGrammarParser();
|
Assert.Throws<ReduceAndShiftConflictException>(() => grammar.ToGrammarParser());
|
||||||
|
|
||||||
ITransformer transformer1 = parser.BeginTransformer;
|
|
||||||
Assert.Equal(3, transformer1.ShiftTable.Count);
|
|
||||||
Assert.Single(transformer1.ReduceTable);
|
|
||||||
Assert.Contains(new NonTerminator(NonTerminatorType.ProgramStruct),transformer1.ShiftTable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ public class KeywordTypeTests
|
||||||
[InlineData("to", KeywordType.To)]
|
[InlineData("to", KeywordType.To)]
|
||||||
[InlineData("do", KeywordType.Do)]
|
[InlineData("do", KeywordType.Do)]
|
||||||
[InlineData("DO", KeywordType.Do)]
|
[InlineData("DO", KeywordType.Do)]
|
||||||
|
[InlineData("true", KeywordType.True)]
|
||||||
|
[InlineData("false", KeywordType.False)]
|
||||||
public void SmokeTest(string input, KeywordType type)
|
public void SmokeTest(string input, KeywordType type)
|
||||||
{
|
{
|
||||||
IEnumerable<SemanticToken> tokensEnumerable = _lexer.Tokenize(new StringSourceReader(input));
|
IEnumerable<SemanticToken> tokensEnumerable = _lexer.Tokenize(new StringSourceReader(input));
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace Canon.Tests.SemanticTests;
|
||||||
|
|
||||||
public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
{
|
{
|
||||||
private readonly TestLogger<TypeCheckVisitor> _logger = new(testOutputHelper);
|
private readonly TestLogger _logger = new(testOutputHelper);
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ConstTypeTest()
|
public void ConstTypeTest()
|
||||||
|
@ -549,6 +549,92 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
Assert.True(visitor.IsError);
|
Assert.True(visitor.IsError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TrueFalseTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var a : boolean;
|
||||||
|
begin
|
||||||
|
a := true;
|
||||||
|
a := false;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.False(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NotTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var a: integer;
|
||||||
|
begin
|
||||||
|
a := 60;
|
||||||
|
write(not a);
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.False(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PascalFunctionTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var a : integer;
|
||||||
|
begin
|
||||||
|
write(a);
|
||||||
|
read(a);
|
||||||
|
writeln(a);
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.False(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FunctionCalculateTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var a : integer;
|
||||||
|
function test : integer;
|
||||||
|
begin
|
||||||
|
test := 1;
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
a := a + test;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.False(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FunctionParameterCalculationTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var a : integer;
|
||||||
|
function test (p : integer) : integer;
|
||||||
|
begin
|
||||||
|
test := p;
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
a := 1 + test(1);
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.False(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
private TypeCheckVisitor CheckType(string program)
|
private TypeCheckVisitor CheckType(string program)
|
||||||
{
|
{
|
||||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||||
|
|
|
@ -1,24 +1,16 @@
|
||||||
using Microsoft.Extensions.Logging;
|
using Canon.Core.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace Canon.Tests.Utils;
|
namespace Canon.Tests.Utils;
|
||||||
|
|
||||||
public class TestLogger<T>(ITestOutputHelper testOutputHelper) : ILogger<T>, IDisposable
|
public class TestLogger(ITestOutputHelper testOutputHelper) : ICompilerLogger
|
||||||
{
|
{
|
||||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
|
||||||
Func<TState, Exception?, string> formatter)
|
Func<TState, Exception?, string> formatter)
|
||||||
{
|
{
|
||||||
testOutputHelper.WriteLine("{0}: {1}", logLevel, formatter(state, exception));
|
testOutputHelper.WriteLine($"{logLevel}: {formatter(state, exception)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsEnabled(LogLevel logLevel) => false;
|
public string Build() => string.Empty;
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDisposable BeginScope<TState>(TState state) where TState : notnull
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ def compile_files():
|
||||||
print("Info: compile ", file)
|
print("Info: compile ", file)
|
||||||
if not (Path("open_set") / file.stem).exists():
|
if not (Path("open_set") / file.stem).exists():
|
||||||
os.system("fpc " + str(file))
|
os.system("fpc " + str(file))
|
||||||
os.system("./pacss -i " + str(file))
|
os.system("./pascc -i " + str(file))
|
||||||
c_file = "./open_set/" + file.stem + ".c"
|
c_file = "./open_set/" + file.stem + ".c"
|
||||||
c_binary = "open_set/" + file.stem + ".out"
|
c_binary = "open_set/" + file.stem + ".out"
|
||||||
os.system("gcc " + c_file + " -o " + c_binary)
|
os.system("gcc " + c_file + " -o " + c_binary)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user