feat: 按照open_set中的示例调整语法 (#71)
添加了构建LR分析表冲突的报错 Reviewed-on: PostGuard/Canon#71
This commit is contained in:
		@@ -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.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) =>
 | 
					        factor.OnProcedureCallGenerator += (_, e) =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (!SymbolTable.TryGetSymbol(e.ProcedureName.IdentifierName, out Symbol? procedure))
 | 
					            if (ValidateProcedureCall(e.ProcedureName, e.Parameters.Expressions, 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))
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        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;
 | 
					                    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;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
            foreach ((Expression expression, PascalParameterType parameterType) in e.Parameters.Expressions.Zip(
 | 
					 | 
				
			||||||
                         functionType.Parameters))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (expression.ExpressionType != parameterType.ParameterType)
 | 
					 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    IsError = true;
 | 
					                    IsError = true;
 | 
				
			||||||
                    logger?.LogError("Parameter expect '{}' but '{}'",
 | 
					                    logger?.LogError("The procedure '{}' returns void.", e.ProcedureName.IdentifierName);
 | 
				
			||||||
                        parameterType.ParameterType.TypeName, expression.ExpressionType);
 | 
					 | 
				
			||||||
                    return;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            factor.FactorType = PascalBasicType.Void;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // factor -> factor
 | 
					        // factor -> not factor
 | 
				
			||||||
        factor.OnNotGenerator += (_, e) =>
 | 
					        factor.OnNotGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; };
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (e.Factor.FactorType != PascalBasicType.Boolean)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                IsError = true;
 | 
					 | 
				
			||||||
                logger?.LogError("The boolean type is expected.");
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            factor.FactorType = PascalBasicType.Boolean;
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 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 (expression.ExpressionType != parameterType.ParameterType)
 | 
					            if (ValidateProcedureCall(procedureCall.ProcedureId, [],
 | 
				
			||||||
 | 
					                    out PascalFunctionType? functionType))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                    IsError = true;
 | 
					                procedureCall.ReturnType = functionType.ReturnType;
 | 
				
			||||||
                    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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                switch (token.TokenType)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    // factor -> num
 | 
				
			||||||
 | 
					                    case SemanticTokenType.Number:
 | 
				
			||||||
                        OnNumberGenerator?.Invoke(this,
 | 
					                        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
 | 
					            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)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TerminatedSyntaxNode terminatedSyntaxNode = Children[0].Convert<TerminatedSyntaxNode>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // factor -> ( expression )
 | 
				
			||||||
 | 
					            if (terminatedSyntaxNode.Token.TokenType == SemanticTokenType.Delimiter)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                OnParethnesisGenerator?.Invoke(this,
 | 
					                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)
 | 
					        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,26 +72,16 @@ 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
 | 
					                    Variable = Children[0].Convert<Variable>(), Expression = Children[2].Convert<Expression>()
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    FunctionName = Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
 | 
					 | 
				
			||||||
                    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>(),
 | 
					                    Condition = Children[1].Convert<Expression>(),
 | 
				
			||||||
                    Sentence = Children[3].Convert<Statement>(),
 | 
					                    Sentence = Children[3].Convert<Statement>(),
 | 
				
			||||||
@@ -112,7 +90,8 @@ public class Statement : NonTerminatedSyntaxNode
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        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>(),
 | 
					                    Iterator = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
 | 
				
			||||||
                    Begin = Children[3].Convert<Expression>(),
 | 
					                    Begin = Children[3].Convert<Expression>(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user