├── .config
└── dotnet-tools.json
├── .editorconfig
├── .github
└── workflows
│ └── dotnet.yml
├── .gitignore
├── Compilers
├── AssemblyInfo.cs
├── CompileException.cs
├── CompilerExceptions.cs
├── Cyjb.Compilers.csproj
├── LICENSE.txt
├── Lexers
│ ├── AcceptState.cs
│ ├── CharClass.cs
│ ├── CharClassCollection.cs
│ ├── CharClassMapBuilder.cs
│ ├── CharClassSet.cs
│ ├── Dfa.cs
│ ├── DfaData.cs
│ ├── DfaDataBuilder.cs
│ ├── DfaState.cs
│ ├── EofBuilder`2.cs
│ ├── ITerminalBuilder`2.cs
│ ├── LexerContext.cs
│ ├── LexerSymbolAttrInfo.cs
│ ├── Lexer`1.cs
│ ├── Lexer`2.cs
│ ├── Nfa.cs
│ ├── NfaBuildResult.cs
│ ├── NfaState.cs
│ ├── NfaStateType.cs
│ ├── TerminalBuilder`2.cs
│ ├── TerminalMatch.cs
│ └── Terminal`1.cs
├── Output.cs
├── OutputTableColumn.cs
├── Parsers
│ ├── AcceptAction.cs
│ ├── Action.cs
│ ├── ActionCollection`1.cs
│ ├── AssociativeType.cs
│ ├── Associativity.cs
│ ├── CandidateAction`1.cs
│ ├── LRItemCollection`1.cs
│ ├── LRItem`1.cs
│ ├── LRState`1.cs
│ ├── ParserConflict`1.cs
│ ├── Parser`1.cs
│ ├── Parser`2.Build.cs
│ ├── Parser`2.cs
│ ├── ProductionBuilder`2.cs
│ ├── Production`1.cs
│ ├── ReduceAction.cs
│ ├── ShiftAction`1.cs
│ ├── StartSymbol`1.cs
│ ├── SymbolStartType.cs
│ ├── SymbolType.cs
│ └── Symbol`1.cs
├── README.md
├── RegularExpressions
│ ├── AlternationExp.cs
│ ├── AnchorExp.cs
│ ├── CharClassExp.cs
│ ├── ConcatenationExp.cs
│ ├── EndOfFileExp.cs
│ ├── LexRegex.cs
│ ├── LiteralExp.cs
│ ├── QuantifierExp.cs
│ ├── RegexCharClass.cs
│ └── RegexParser.cs
├── Resources.cs
├── Resources.resx
├── Resources.tt
└── Resources.zh-Hans.resx
├── Cyjb.Compilers.sln
├── Design
├── CompilerTemplate.t4
├── Cyjb.Compilers.Design.csproj
├── LICENSE.txt
├── Lexers
│ ├── LexerContextAttribute.cs
│ ├── LexerInclusiveContextAttribute.cs
│ ├── LexerRegexAttribute.cs
│ ├── LexerRejectableAttribute.cs
│ └── LexerSymbolAttribute.cs
├── Parsers
│ ├── ParserLeftAssociateAttribute.cs
│ ├── ParserNonAssociateAttribute.cs
│ ├── ParserProductionAttribute.cs
│ ├── ParserRightAssociateAttribute.cs
│ └── ParserStartAttribute.cs
├── README.md
└── Tools
│ ├── Cyjb.Compilers.Design.dll
│ ├── Cyjb.Compilers.Runtime.dll
│ ├── Cyjb.Compilers.dll
│ ├── Cyjb.dll
│ ├── Generator.deps.json
│ ├── Generator.dll
│ ├── Generator.runtimeconfig.json
│ ├── Microsoft.CodeAnalysis.CSharp.dll
│ ├── Microsoft.CodeAnalysis.dll
│ ├── System.Collections.Immutable.dll
│ ├── System.Reflection.Metadata.dll
│ └── zh-Hans
│ ├── Cyjb.Compilers.Runtime.resources.dll
│ ├── Cyjb.Compilers.resources.dll
│ ├── Cyjb.resources.dll
│ ├── Generator.resources.dll
│ ├── Microsoft.CodeAnalysis.CSharp.resources.dll
│ └── Microsoft.CodeAnalysis.resources.dll
├── Generator
├── CodeAnalysis.CSharp
│ ├── AttributeArguments.cs
│ ├── AttributeModel.cs
│ ├── AttributeParameterInfo.cs
│ ├── AttributeSyntaxUtil.cs
│ ├── Builders
│ │ ├── ArgumentBuilder.cs
│ │ ├── ArgumentListBuilder.cs
│ │ ├── AttributeArgumentBuilder.cs
│ │ ├── AttributeArgumentListBuilder.cs
│ │ ├── AttributeBuilder.cs
│ │ ├── AttributeListBuilder.cs
│ │ ├── Declarations
│ │ │ ├── BaseMethodDeclarationBuilder.cs
│ │ │ ├── ClassDeclarationBuilder.cs
│ │ │ ├── ConstructorDeclarationBuilder.cs
│ │ │ ├── FieldDeclarationBuilder.cs
│ │ │ ├── MemberDeclarationBuilder.cs
│ │ │ └── MethodDeclarationBuilder.cs
│ │ ├── DocumentationCommentTriviaBuilder.cs
│ │ ├── Expressions
│ │ │ ├── ArrayCreationExpressionBuilder.cs
│ │ │ ├── AssignmentExpressionBuilder.cs
│ │ │ ├── BinaryExpressionBuilder.cs
│ │ │ ├── CastExpressionBuilder.cs
│ │ │ ├── ElementAccessExpressionBuilder.cs
│ │ │ ├── ExpressionBuilder.cs
│ │ │ ├── InitializerExpressionBuilder.cs
│ │ │ ├── InvocationExpressionBuilder.cs
│ │ │ ├── LambdaExpressionBuilder.cs
│ │ │ ├── MemberAccessExpressionBuilder.cs
│ │ │ ├── NameBuilder.cs
│ │ │ ├── ObjectCreationExpressionBuilder.cs
│ │ │ ├── ParenthesizedExpressionBuilder.cs
│ │ │ ├── PrefixUnaryExpressionBuilder.cs
│ │ │ ├── TypeBuilder.cs
│ │ │ └── TypeOfExpressionBuilder.cs
│ │ ├── ModifierBuilder.cs
│ │ ├── ParameterBuilder.cs
│ │ ├── ParameterListBuilder.cs
│ │ ├── Pattern
│ │ │ ├── BinaryPatternBuilder.cs
│ │ │ ├── PatternBuilder.cs
│ │ │ └── RelationalPatternBuilder.cs
│ │ ├── SeparatedListUtils.cs
│ │ └── Statements
│ │ │ ├── BlockBuilder.cs
│ │ │ ├── BreakStatementBuilder.cs
│ │ │ ├── ExpressionStatementBuilder.cs
│ │ │ ├── GotoStatementBuilder.cs
│ │ │ ├── IfStatementBuilder.cs
│ │ │ ├── LabeledStatementBuilder.cs
│ │ │ ├── LocalDeclarationStatementBuilder.cs
│ │ │ ├── ReturnStatementBuilder.cs
│ │ │ ├── StatementBuilder.cs
│ │ │ ├── SwitchSectionBuilder.cs
│ │ │ ├── SwitchStatementBuilder.cs
│ │ │ └── WhileStatementBuilder.cs
│ ├── CSharpException.cs
│ ├── ExpressionSyntaxUtil.cs
│ ├── IndentDetector.cs
│ ├── NameSyntaxUtil.cs
│ ├── NamespaceRewriter.cs
│ ├── ParameterSyntaxUtil.cs
│ ├── SyntaxBuilder.cs
│ ├── SyntaxFormat.cs
│ ├── SyntaxNodeUtils.cs
│ ├── SyntaxTokenUtils.cs
│ └── XmlNodeSyntaxOrString.cs
├── Controller.cs
├── ControllerVisitor.cs
├── Cyjb.Compilers.Generator.csproj
├── LICENSE.txt
├── Lexers
│ ├── LexerController.CharClass.cs
│ ├── LexerController.Contexts.cs
│ ├── LexerController.Terminals.cs
│ ├── LexerController.cs
│ └── LexerSymbolAttrInfo.cs
├── Parsers
│ ├── ParserController.Goto.cs
│ ├── ParserController.KindMap.cs
│ ├── ParserController.Productions.cs
│ ├── ParserController.States.cs
│ └── ParserController.cs
├── Program.cs
├── Properties
│ ├── PublishProfiles
│ │ └── Publish.pubxml
│ └── launchSettings.json
├── README.md
├── Resources.cs
├── Resources.resx
├── Resources.tt
├── Resources.zh-Hans.resx
├── SymbolKind.cs
├── TransformationContext.cs
└── tests
│ ├── TestCalcLexer.cs
│ ├── TestEscapeStrController.cs
│ ├── TestEscapeStrController.second.cs
│ ├── TestProductionController.cs
│ ├── TestProductionParser.cs
│ ├── TestProductionParser.designed.cs
│ ├── TestProductionParser.tt
│ ├── TestSymbolValueLexer.cs
│ └── UnitTestTemplateDiagnostics.template.cs
├── README.md
├── Runtime
├── AssemblyInfo.cs
├── Cyjb.Compilers.Runtime.csproj
├── LICENSE.txt
├── Lexers
│ ├── CharClassMap.cs
│ ├── ContextData.cs
│ ├── Core
│ │ ├── BasicCore`1.cs
│ │ ├── BasicDebugCore.cs
│ │ ├── FixedTrailingCore`1.cs
│ │ ├── FixedTrailingDebugCore`1.cs
│ │ ├── LexerCore`1.cs
│ │ ├── LexerStateInfo.cs
│ │ ├── RejectableCore`1.cs
│ │ ├── RejectableDebugCore`1.cs
│ │ ├── RejectableTrailingCore`1.cs
│ │ └── RejectableTrailingDebugCore`1.cs
│ ├── DfaStateData.cs
│ ├── ILexerFactory`1.cs
│ ├── LexerController`1.cs
│ ├── LexerData`1.cs
│ ├── LexerFactory`1.cs
│ ├── LexerFactory`2.cs
│ ├── LexerRunner`1.cs
│ ├── LexerTokenizer`1.cs
│ ├── RejectOptions.cs
│ ├── TerminalData`1.cs
│ └── TrailingType.cs
├── Parsers
│ ├── EmptyTokenizer`1.cs
│ ├── IParserFactory`1.cs
│ ├── InsertTokenCandidate.cs
│ ├── LRParser`1.cs
│ ├── ParseOptions.cs
│ ├── ParserAction.cs
│ ├── ParserActionType.cs
│ ├── ParserController`1.cs
│ ├── ParserData.cs
│ ├── ParserData`1.cs
│ ├── ParserFactory`1.cs
│ ├── ParserFactory`2.cs
│ ├── ParserStateData`1.cs
│ ├── ProductionAction.cs
│ ├── ProductionData`1.cs
│ └── SymbolOptions.cs
├── README.md
├── Resources.cs
├── Resources.resx
├── Resources.tt
├── Resources.zh-Hans.resx
└── Text
│ ├── EnumerableTokenizer`1.cs
│ ├── ITokenParser`1.cs
│ ├── ITokenizer`1.cs
│ ├── MissingTokenError.cs
│ ├── ParseStatus.cs
│ ├── ParserNode`1.cs
│ ├── SourceReader
│ ├── PartialSourceReader.cs
│ ├── SourceReader.cs
│ ├── StringSourceReader.cs
│ └── StringViewSourceReader.cs
│ ├── TokenCollection`1.cs
│ ├── TokenDisplayNameAttribute.cs
│ ├── TokenParseError.cs
│ ├── TokenSpanComparer`1.cs
│ ├── Token`1.DisplayName.cs
│ ├── Token`1.cs
│ ├── TokenizeError.cs
│ ├── UnexpectedTokenError.cs
│ └── Utils.cs
├── TestCompilers
├── Calc.cs
├── CompilerTemplate.t4
├── Lexers
│ ├── LexerRunnerContext.cs
│ ├── Shortest
│ │ ├── TestShortestLexer1.cs
│ │ ├── TestShortestLexer1.designed.cs
│ │ ├── TestShortestLexer1.tt
│ │ ├── TestShortestLexer2.cs
│ │ ├── TestShortestLexer2.designed.cs
│ │ ├── TestShortestLexer2.tt
│ │ ├── TestShortestLexer3.cs
│ │ ├── TestShortestLexer3.designed.cs
│ │ ├── TestShortestLexer3.tt
│ │ ├── TestShortestLexer4.cs
│ │ ├── TestShortestLexer4.designed.cs
│ │ ├── TestShortestLexer4.tt
│ │ └── UnitTestShortestLexer.cs
│ ├── TestCalcLexer.cs
│ ├── TestCalcLexer.designed.cs
│ ├── TestCalcLexer.tt
│ ├── TestCalcRunnerLexer.cs
│ ├── TestCalcRunnerLexer.designed.cs
│ ├── TestCalcRunnerLexer.tt
│ ├── TestEscapeStrLexer.cs
│ ├── TestEscapeStrLexer.designed.cs
│ ├── TestEscapeStrLexer.tt
│ ├── TestProductionLexer.cs
│ ├── TestProductionLexer.designed.cs
│ ├── TestProductionLexer.tt
│ ├── TestStrLexer.cs
│ ├── TestStrLexer.designed.cs
│ ├── TestStrLexer.tt
│ ├── TestSymbolValueLexer.cs
│ ├── TestSymbolValueLexer.designed.cs
│ ├── TestSymbolValueLexer.tt
│ ├── Trailing
│ │ ├── TestTrailingLexer1.cs
│ │ ├── TestTrailingLexer1.designed.cs
│ │ ├── TestTrailingLexer1.tt
│ │ ├── TestTrailingLexer2.cs
│ │ ├── TestTrailingLexer2.designed.cs
│ │ ├── TestTrailingLexer2.tt
│ │ ├── TestTrailingLexer3.cs
│ │ ├── TestTrailingLexer3.designed.cs
│ │ ├── TestTrailingLexer3.tt
│ │ ├── TestTrailingLexerEOL.cs
│ │ ├── TestTrailingLexerEOL.designed.cs
│ │ ├── TestTrailingLexerEOL.tt
│ │ └── UnitTestTrailingLexer.cs
│ ├── UnitTestCharClassCollection.cs
│ ├── UnitTestCharClassMap.cs
│ ├── UnitTestLexer.cancel.cs
│ ├── UnitTestLexer.cs
│ ├── UnitTestLexer.merge.cs
│ ├── UnitTestLexer.rejectable.cs
│ ├── UnitTestLexer.token.cs
│ ├── UnitTestLexerRunner.cs
│ ├── UnitTestNFA.cs
│ ├── UnitTestTemplateDiagnostics.cs
│ └── UnitTestTemplateDiagnostics.template.cs
├── Parsers
│ ├── TestCalcParser.cs
│ ├── TestCalcParser.designed.cs
│ ├── TestCalcParser.tt
│ ├── TestProductionParser.cs
│ ├── TestProductionParser.designed.cs
│ ├── TestProductionParser.tt
│ ├── UnitTestParser.cancel.cs
│ ├── UnitTestParser.cs
│ ├── UnitTestParser.option.cs
│ ├── UnitTestParser.recover.cs
│ └── UnitTestParser.start.cs
├── ProductionKind.cs
├── RegularExpressions
│ ├── UnitTestLexRegex.cs
│ └── UnitTestRegexCharClass.cs
├── TestCompilers.csproj
├── TestKind.cs
└── Text
│ ├── UnitTestSourceReader.cs
│ └── UnitTestToken`1.cs
└── generate-code-coverage-report.ps1
/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "dotnet-reportgenerator-globaltool": {
6 | "version": "5.1.18",
7 | "commands": [
8 | "reportgenerator"
9 | ]
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*] # 对于所有文件
2 | # 缩进风格
3 | indent_style = tab
4 | # 缩进宽度
5 | tab_width = 4
6 | # 文件编码格式
7 | charset = utf-8
8 | # 行尾格式
9 | end_of_line = crlf
10 | # 文件结尾添加换行符
11 | insert_final_newline = true
12 |
13 | [*.cs]
14 | # IDE0180: 使用元组交换值
15 | csharp_style_prefer_tuple_swap = false
16 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a .NET project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
3 |
4 | name: .NET
5 |
6 | on:
7 | push:
8 | branches: [ "master" ]
9 | pull_request:
10 | branches: [ "master" ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: windows-latest
16 | strategy:
17 | matrix:
18 | dotnet-version: [ '6.0.x' ]
19 |
20 | steps:
21 | - uses: actions/checkout@v3
22 | - name: Setup .NET ${{ matrix.dotnet-version }}
23 | uses: actions/setup-dotnet@v3
24 | with:
25 | dotnet-version: ${{ matrix.dotnet-version }}
26 | - name: Restore dependencies
27 | run: dotnet restore
28 | - name: Build
29 | run: dotnet build --no-restore
30 | - name: Test
31 | run: dotnet test --no-build --verbosity normal --logger trx --results-directory "TestResults-${{ matrix.dotnet-version }}"
32 | - name: Upload test results
33 | uses: actions/upload-artifact@v4
34 | with:
35 | name: dotnet-results-${{ matrix.dotnet-version }}
36 | path: TestResults-${{ matrix.dotnet-version }}
37 | # Use always() to always run this step to publish test results when there are test failures
38 | if: ${{ always() }}
39 | - name: Upload coverage reports to Codecov
40 | uses: codecov/codecov-action@v3
41 | with:
42 | token: ${{ secrets.CODECOV_TOKEN }}
43 | fail_ci_if_error: true
44 | paths: ./**/coverage.opencover.xml
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders
2 | bin
3 | obj
4 | *.pdb
5 | .vs
6 |
7 | # mstest test results
8 | TestResults
9 | CodeCoverage
10 | coverage.cobertura.xml
11 |
12 | # test project
13 | ConsoleTest
14 |
15 | # files
16 | *.suo
17 | *.snk
18 | *.vspx
19 | *.user
20 | update-version.ps1
21 | publish.ps1
22 |
--------------------------------------------------------------------------------
/Compilers/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // 有关程序集的常规信息通过以下
5 | // 特性集控制。更改这些特性值可修改
6 | // 与程序集关联的信息。
7 | [assembly: AssemblyTrademark("CYJB")]
8 | [assembly: AssemblyCulture("")]
9 | [assembly: CLSCompliant(false)]
10 |
11 | // 将 ComVisible 设置为 false 使此程序集中的类型
12 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
13 | // 则将该类型上的 ComVisible 特性设置为 true。
14 | [assembly: ComVisible(false)]
15 |
16 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
17 | [assembly: Guid("12f9eef0-249a-41be-a68f-72c7b6f426b1")]
18 |
19 |
--------------------------------------------------------------------------------
/Compilers/CompileException.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers;
2 |
3 | ///
4 | /// 表示编译相关的异常。
5 | ///
6 | public sealed class CompileException : Exception
7 | {
8 | ///
9 | /// 使用指定的错误消息初始化 类的新实例。
10 | ///
11 | /// 错误消息。
12 | public CompileException(string message) : base(message) { }
13 | }
14 |
--------------------------------------------------------------------------------
/Compilers/CompilerExceptions.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers;
2 |
3 | ///
4 | /// 提供用于异常处理的辅助方法。
5 | ///
6 | internal static class CompilerExceptions
7 | {
8 | ///
9 | /// 返回重复的词法分析上下文的异常。
10 | ///
11 | /// 词法分析上下文名称。
12 | /// 对象。
13 | public static ArgumentException DuplicateLexerContext(string? context)
14 | {
15 | return new ArgumentException(Resources.DuplicateLexerContext(context));
16 | }
17 |
18 | ///
19 | /// 返回产生式的优先级必须是一个终结符的异常。
20 | ///
21 | /// 异常的符号名称。
22 | /// 对象。
23 | public static InvalidOperationException PrecedenceMustBeTerminal(string name)
24 | {
25 | return new InvalidOperationException(Resources.PrecedenceMustBeTerminal(name));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Compilers/Cyjb.Compilers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | enable
5 | enable
6 | True
7 | True
8 | https://github.com/CYJB/Cyjb.Compilers
9 | 提供编译相关功能
10 | Copyright (c) 2022, CYJB
11 | README.md
12 | LICENSE.txt
13 | en
14 | $(VersionPrefix)
15 | 1.0.23
16 | Cyjb.Compilers
17 | CYJB
18 | true
19 | snupkg
20 |
21 |
22 | ../CYJB_Code_Key.snk
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | True
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | True
40 | True
41 | Resources.tt
42 |
43 |
44 |
45 |
46 | TextTemplatingFileGenerator
47 | Resources.cs
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/Compilers/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013, CYJB
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice, this
11 | list of conditions and the following disclaimer in the documentation and/or
12 | other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/Compilers/Lexers/AcceptState.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 表示一个接受状态。
5 | ///
6 | internal struct AcceptState
7 | {
8 | ///
9 | /// 被接受的符号标识符。
10 | ///
11 | public IList SymbolIndex;
12 | ///
13 | /// 当前的源文件索引。
14 | ///
15 | public int Index;
16 |
17 | ///
18 | /// 使用被接受的符号标识符和源文件索引初始化 结构的新实例。
19 | ///
20 | /// 被接受的符号标识符。
21 | /// 当前的源文件索引。
22 | internal AcceptState(IList symbolIndex, int index)
23 | {
24 | SymbolIndex = symbolIndex;
25 | Index = index;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Compilers/Lexers/CharClass.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Collections;
2 |
3 | namespace Cyjb.Compilers.Lexers;
4 |
5 | ///
6 | /// 表示一个字符类。
7 | ///
8 | public class CharClass
9 | {
10 | ///
11 | /// 使用指定的字符集合初始化。
12 | ///
13 | /// 当前字符类的索引。
14 | /// 当前字符类包含的字符集合。
15 | internal CharClass(int index, CharSet chars)
16 | {
17 | Index = index;
18 | Chars = chars;
19 | Containers = new HashSet();
20 | }
21 |
22 | ///
23 | /// 获取当前字符类的索引。
24 | ///
25 | public int Index { get; internal set; }
26 | ///
27 | /// 获取当前字符类包含的字符集合。
28 | ///
29 | public CharSet Chars { get; }
30 | ///
31 | /// 获取包含当前字符类的字符类集合。
32 | ///
33 | internal ISet Containers { get; }
34 |
35 | ///
36 | /// 分割当前字符类。
37 | ///
38 | /// 新字符类的索引。
39 | /// 新字符类包含的字符集合。
40 | /// 新的字符类。
41 | internal CharClass Split(int index, CharSet chars)
42 | {
43 | // 1. 剔除被分割的部分。
44 | Chars.ExceptWith(chars);
45 | // 2. 创建新字符类。
46 | CharClass newItem = new(index, chars);
47 | if (chars.Count > 1)
48 | {
49 | // 复制所属字符类集合。
50 | newItem.Containers.UnionWith(Containers);
51 | }
52 | // 3. 更新现有字符类。
53 | foreach (CharClassSet charClass in Containers)
54 | {
55 | charClass.Add(newItem);
56 | }
57 | // 4. 如果分割后的现有字符类只包含一个字符,无法继续分割,那么可以移除 Containers
58 | if (Chars.Count == 1)
59 | {
60 | Containers.Clear();
61 | }
62 | return newItem;
63 | }
64 |
65 | ///
66 | /// 返回当前对象的字符串表示形式。
67 | ///
68 | /// 当前对象的字符串表示形式。
69 | public override string ToString()
70 | {
71 | return Chars.ToString();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Compilers/Lexers/DfaData.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// DFA 的数据。
5 | ///
6 | public sealed class DfaData
7 | {
8 | ///
9 | /// 使用指定的数据初始化 类的新实例。
10 | ///
11 | /// DFA 的状态列表。
12 | /// DFA 的状态转移。
13 | public DfaData(int[] states, int[] trans)
14 | {
15 | States = states;
16 | Trans = trans;
17 | }
18 |
19 | ///
20 | /// 获取 DFA 的状态列表。
21 | ///
22 | public int[] States { get; }
23 | ///
24 | /// 获取 DFA 的状态转移。
25 | ///
26 | /// 使用 trans[i] 表示 check,trans[i+1] 表示 next。
27 | public int[] Trans { get; }
28 | }
29 |
--------------------------------------------------------------------------------
/Compilers/Lexers/ITerminalBuilder`2.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 词法分析的终结符构造器。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | /// 词法分析控制器的类型。
8 | public interface ITerminalBuilder
9 | where T : struct
10 | where TController : LexerController, new()
11 | {
12 | ///
13 | /// 设置正则表达式的上下文。
14 | ///
15 | /// 正则表达式的上下文。
16 | /// 终结符的构造器。
17 | ITerminalBuilder Context(params string[] contexts);
18 |
19 | ///
20 | /// 设置终结符的词法单元类型。
21 | ///
22 | /// 词法单元的类型。
23 | /// 终结符的构造器。
24 | ITerminalBuilder Kind(T kind);
25 |
26 | ///
27 | /// 设置终结符的值。
28 | ///
29 | /// 词法单元的值。
30 | /// 终结符的构造器。
31 | ITerminalBuilder Value(object? value);
32 |
33 | ///
34 | /// 设置使用终结符的最短匹配。
35 | ///
36 | /// 终结符的构造器。
37 | /// 默认都会使用正则表达式的最长匹配,允许指定为使用最短匹配,
38 | /// 会在遇到第一个匹配时立即返回结果。
39 | ITerminalBuilder UseShortest();
40 |
41 | ///
42 | /// 设置终结符的动作。
43 | ///
44 | /// 终结符的动作。
45 | /// 终结符的构造器。
46 | void Action(Action action);
47 | }
48 |
--------------------------------------------------------------------------------
/Compilers/Lexers/LexerContext.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 词法分析器上下文的类型。
5 | ///
6 | internal enum LexerContextType
7 | {
8 | ///
9 | /// 包含型上下文,默认上下文的规则也会有效。
10 | ///
11 | Inclusive,
12 | ///
13 | /// 排除型上下文,默认上下文的规则无效。
14 | ///
15 | Exclusive
16 | }
17 |
18 | ///
19 | /// 表示词法分析器的上下文。
20 | ///
21 | internal sealed class LexerContext
22 | {
23 | ///
24 | /// 使用指定的上下文信息初始化 的新实例。
25 | ///
26 | /// 上下文的索引。
27 | /// 上下文的标签。
28 | /// 上下文的类型。
29 | public LexerContext(int index, string label, LexerContextType type)
30 | {
31 | Index = index;
32 | Label = label;
33 | Type = type;
34 | }
35 |
36 | ///
37 | /// 获取上下文的索引。
38 | ///
39 | public int Index { get; }
40 | ///
41 | /// 获取上下文的标签。
42 | ///
43 | public string Label { get; }
44 | ///
45 | /// 获取上下文的类型。
46 | ///
47 | public LexerContextType Type { get; }
48 | ///
49 | /// 上下文的 EOF 动作。
50 | ///
51 | public Delegate? EofAction { get; set; }
52 | ///
53 | /// 上下文的 EOF 动作的值。
54 | ///
55 | public object? EofValue { get; set; }
56 |
57 | ///
58 | /// 返回词法分析器的上下文数据。
59 | ///
60 | /// 词法分析器的上下文数据。
61 | public ContextData GetData()
62 | {
63 | return new ContextData(Index, Label, EofAction, EofValue);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Compilers/Lexers/Lexer`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 表示词法分析规则。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | ///
8 | /// 泛型参数 一般是一个枚举类型,用于标识词法单元。
9 | /// 对于词法分析中的冲突,总是选择最长的词素。如果最长的词素可以与多个模式匹配,
10 | /// 则选择最先被定义的模式。关于词法分析的相关信息,请参考我的系列博文
11 | ///
12 | /// 《C# 词法分析器(一)词法分析介绍》,词法分析器的使用指南请参见
13 | ///
14 | /// 《C# 词法分析器(七)总结》。
15 | ///
16 | /// 下面简单的构造一个数学算式的词法分析器:
17 | ///
18 | /// enum Calc { Id, Add, Sub, Mul, Div, Pow, LBrace, RBrace }
19 | /// Lexer<Calc> lexer = new Lexer<Calc>();
20 | /// // 终结符的定义。
21 | /// lexer.DefineSymbol("[0-9]+").Kind(Calc.Id).Action(c => c.Accept(int.Parse(c.Text)));
22 | /// lexer.DefineSymbol("\\+").Kind(Calc.Add);
23 | /// lexer.DefineSymbol("\\-").Kind(Calc.Sub);
24 | /// lexer.DefineSymbol("\\*").Kind(Calc.Mul);
25 | /// lexer.DefineSymbol("\\/").Kind(Calc.Div);
26 | /// lexer.DefineSymbol("\\^").Kind(Calc.Pow);
27 | /// lexer.DefineSymbol("\\(").Kind(Calc.LBrace);
28 | /// lexer.DefineSymbol("\\)").Kind(Calc.RBrace);
29 | /// // 吃掉所有空白。
30 | /// lexer.DefineSymbol("\\s");
31 | /// ILexerFactory<Calc> lexerFactory = lexer.GetFactory();
32 | /// // 要分析的源文件。
33 | /// string source = "1 + 20 * 3 / 4*(5+6)";
34 | /// ITokenizer<Calc> tokenizer = lexerFactory.CreateTokenizer(source);
35 | /// // 构造词法分析器。
36 | /// foreach (Token<Calc> token in tokenizer)
37 | /// {
38 | /// Console.WriteLine(token);
39 | /// }
40 | ///
41 | ///
42 | ///
43 | /// 《C# 词法分析器(一)词法分析介绍》
44 | ///
45 | /// 《C# 词法分析器(七)总结》
46 | public sealed class Lexer : Lexer>
47 | where T : struct
48 | { }
49 |
--------------------------------------------------------------------------------
/Compilers/Lexers/NfaBuildResult.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// NFA 的构造结果。
5 | ///
6 | public struct NfaBuildResult
7 | {
8 | ///
9 | /// 结果的首状态。
10 | ///
11 | public NfaState Head;
12 | ///
13 | /// 结果的尾状态。
14 | ///
15 | public NfaState Tail;
16 | ///
17 | /// 是否是行首限定的。
18 | ///
19 | public bool BeginningOfLine;
20 | }
21 |
--------------------------------------------------------------------------------
/Compilers/Lexers/NfaStateType.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 表示 NFA 状态的类型。
5 | ///
6 | public enum NfaStateType
7 | {
8 | ///
9 | /// 普通状态。
10 | ///
11 | Normal,
12 | ///
13 | /// 向前看状态的头。
14 | ///
15 | TrailingHead,
16 | ///
17 | /// 向前看状态。
18 | ///
19 | Trailing
20 | }
21 |
--------------------------------------------------------------------------------
/Compilers/Lexers/TerminalMatch.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.RegularExpressions;
2 |
3 | namespace Cyjb.Compilers.Lexers;
4 |
5 | ///
6 | /// 表示词法分析中的终结符的匹配信息。
7 | ///
8 | internal sealed class TerminalMatch
9 | {
10 | ///
11 | /// 使用终结符的正则表达式初始化 类的新实例。
12 | ///
13 | /// 终结符对应的正则表达式。
14 | public TerminalMatch(LexRegex regex)
15 | {
16 | RegularExpression = regex;
17 | Context = new HashSet();
18 | }
19 |
20 | ///
21 | /// 获取当前终结符对应的正则表达式。
22 | ///
23 | public LexRegex RegularExpression { get; }
24 | ///
25 | /// 获取定义当前终结符的上下文。
26 | ///
27 | /// 定义当前终结符的上下文。
28 | public HashSet Context { get; }
29 | }
30 |
--------------------------------------------------------------------------------
/Compilers/Output.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace Cyjb.Compilers;
4 |
5 | ///
6 | /// 提供文本输出的工具方法。
7 | ///
8 | internal class Output
9 | {
10 | ///
11 | /// 返回索引的宽度。
12 | ///
13 | /// 索引的总个数。
14 | /// 索引位置的宽度。
15 | public static int GetIndexWidth(int count)
16 | {
17 | if (count <= 10)
18 | {
19 | return 1;
20 | }
21 | return (int)Math.Log10(count - 1) + 1;
22 | }
23 |
24 | ///
25 | /// 输出指定的表格。
26 | ///
27 | /// 要输出到的文本。
28 | /// 表格的列定义。
29 | /// 表格数据。
30 | public static void AppendTable(StringBuilder text, IList columns, IList table)
31 | {
32 | int rowCount = table.Count;
33 | int indexWidth = GetIndexWidth(rowCount);
34 | text.Append(new string(' ', indexWidth));
35 | int columnCount = columns.Count;
36 | int[] widths = new int[columnCount];
37 | for (int i = 0; i < columnCount; i++)
38 | {
39 | OutputTableColumn column = columns[i];
40 | string name = column.Name;
41 | int width = 0;
42 | if (column.IsFixedWidth)
43 | {
44 | width = table.Select((row) => row[i].Length).Max();
45 | if (width < name.Length)
46 | {
47 | width = name.Length;
48 | }
49 | // 使用两个空格分割列。
50 | width += 2;
51 | widths[i] = width;
52 | }
53 | text.AppendFormat(name.PadLeft(width));
54 | }
55 | text.AppendLine();
56 | for (int i = 0; i < rowCount; i++)
57 | {
58 | string[] row = table[i];
59 | text.AppendFormat(i.ToString().PadLeft(indexWidth));
60 | for (int j = 0; j < columnCount; j++)
61 | {
62 | text.AppendFormat(row[j].PadLeft(widths[j]));
63 | }
64 | text.AppendLine();
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Compilers/OutputTableColumn.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers;
2 |
3 | ///
4 | /// 文本输出的列定义。
5 | ///
6 | internal class OutputTableColumn
7 | {
8 | ///
9 | /// 使用列的名称初始化 类的新实例。
10 | ///
11 | /// 列的名称。
12 | /// 列是否是固定宽度。
13 | public OutputTableColumn(string name, bool isFixedWidth = true)
14 | {
15 | Name = name;
16 | IsFixedWidth = isFixedWidth;
17 | }
18 |
19 | ///
20 | /// 获取列的名称。
21 | ///
22 | public string Name { get; }
23 | ///
24 | /// 获取列是否是固定宽度。
25 | ///
26 | public bool IsFixedWidth { get;private set; }
27 | }
28 |
--------------------------------------------------------------------------------
/Compilers/Parsers/AcceptAction.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示 LR 语法分析器的接受动作。
5 | ///
6 | internal class AcceptAction : Action
7 | {
8 | ///
9 | /// 高优先级接受动作的实例。
10 | ///
11 | public static readonly AcceptAction HighPriority = new(true);
12 | ///
13 | /// 低优先级接受动作的实例。
14 | ///
15 | public static readonly AcceptAction LowPriority = new(false);
16 |
17 | private AcceptAction(bool isHighPriority)
18 | {
19 | IsHighPriority = isHighPriority;
20 | }
21 |
22 | ///
23 | /// 获取当前动作是否是成功动作。
24 | ///
25 | public override bool IsSuccessAction => true;
26 | ///
27 | /// 获取当前动作是否是高优先级的。
28 | ///
29 | public bool IsHighPriority { get; }
30 |
31 | ///
32 | /// 返回当前动作对应的 。
33 | ///
34 | /// 当前动作对应的 。
35 | public override ParserAction ToParserAction()
36 | {
37 | return ParserAction.Accept;
38 | }
39 |
40 | ///
41 | /// 返回当前对象是否等于同一类型的另一对象。
42 | ///
43 | /// 要比较的对象。
44 | /// 如果当前对象等于 ,则为 true;否则为 false。
45 | public override bool Equals(Action? other)
46 | {
47 | return other is AcceptAction;
48 | }
49 |
50 | ///
51 | /// 返回当前对象的哈希值。
52 | ///
53 | /// 当前对象的哈希值。
54 | public override int GetHashCode()
55 | {
56 | return 38189501;
57 | }
58 |
59 | ///
60 | /// 返回当前对象的字符串表示。
61 | ///
62 | /// 当前对象的字符串表示。
63 | public override string ToString()
64 | {
65 | return "acc";
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Compilers/Parsers/AssociativeType.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示终结符结合性的类型。
5 | ///
6 | public enum AssociativeType
7 | {
8 | ///
9 | /// 非结合的。
10 | ///
11 | NonAssociate,
12 | ///
13 | /// 左结合的。
14 | ///
15 | Left,
16 | ///
17 | /// 右结合的。
18 | ///
19 | Right
20 | }
21 |
--------------------------------------------------------------------------------
/Compilers/Parsers/CandidateAction`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示候选动作。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | internal class CandidateAction
8 | where T : struct
9 | {
10 | ///
11 | /// 使用指定的候选信息初始化 类的新实例。
12 | ///
13 | /// 候选项。
14 | /// 候选动作。
15 | public CandidateAction(LRItem item, Action action)
16 | {
17 | Item = item;
18 | Action = action;
19 | }
20 |
21 | ///
22 | /// 获取候选项。
23 | ///
24 | public LRItem Item { get; }
25 | ///
26 | /// 获取候选动作。
27 | ///
28 | public Action Action { get; }
29 | }
30 |
--------------------------------------------------------------------------------
/Compilers/Parsers/ProductionBuilder`2.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示文法的产生式构造器。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | /// 语法分析控制器的类型。
8 | public sealed class ProductionBuilder
9 | where T : struct
10 | where TController : ParserController, new()
11 | {
12 | ///
13 | /// 关联到的语法分析器。
14 | ///
15 | private readonly Parser parser;
16 | ///
17 | /// 关联到的产生式。
18 | ///
19 | private readonly Production production;
20 |
21 | ///
22 | /// 使用语法分析器和产生式初始化 类的新实例。
23 | ///
24 | /// 关联到的语法分析器。
25 | /// 关联到的产生式。
26 | internal ProductionBuilder(Parser parser, Production production)
27 | {
28 | this.parser = parser;
29 | this.production = production;
30 | }
31 |
32 | ///
33 | /// 设置当前产生式的动作。
34 | ///
35 | /// 当前产生式体的动作。
36 | /// 当前产生式。
37 | public ProductionBuilder Action(Func action)
38 | {
39 | production.Action = action;
40 | return this;
41 | }
42 |
43 | ///
44 | /// 设置当前产生式的优先级与指定的非终结符相同。
45 | ///
46 | /// 非终结符的标识符。
47 | /// 当前产生式。
48 | public ProductionBuilder Prec(T kind)
49 | {
50 | production.Precedence = parser.GetOrCreateSymbol(kind);
51 | return this;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Compilers/Parsers/Production`1.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace Cyjb.Compilers.Parsers;
4 |
5 | ///
6 | /// 表示文法的产生式。
7 | ///
8 | /// 词法单元标识符的类型,一般是一个枚举类型。
9 | internal sealed class Production
10 | where T : struct
11 | {
12 | ///
13 | /// 使用产生式的索引和内容初始化 类的新实例。
14 | ///
15 | /// 产生式的索引。
16 | /// 产生式头。
17 | /// 产生式体。
18 | internal Production(int index, Symbol head, params Symbol[] body)
19 | {
20 | Index = index;
21 | Head = head;
22 | Body = body;
23 | }
24 |
25 | ///
26 | /// 获取产生式的索引。
27 | ///
28 | /// 产生式的索引。
29 | internal int Index { get; }
30 | ///
31 | /// 获取产生式头。
32 | ///
33 | /// 产生式的头。
34 | internal Symbol Head { get; }
35 | ///
36 | /// 获取产生式体。
37 | ///
38 | /// 产生式体。
39 | internal Symbol[] Body { get; }
40 | ///
41 | /// 获取或设置产生式的动作。
42 | ///
43 | /// 产生式的动作。
44 | internal Delegate? Action { get; set; }
45 | ///
46 | /// 获取或设置表示当前产生式的结合性的非终结符。
47 | ///
48 | /// 表示当前产生式的结合性的非终结符的标识符。
49 | internal Symbol? Precedence { get; set; }
50 |
51 | ///
52 | /// 返回当前产生式的数据。
53 | ///
54 | /// 当前产生式的数据。
55 | public ProductionData GetData()
56 | {
57 | return new ProductionData(Head.Index, Head.Kind, Action, Body.Select(s => s.Kind).ToArray());
58 | }
59 |
60 | ///
61 | /// 返回当前对象的字符串表示形式。
62 | ///
63 | /// 当前对象的字符串表示形式。
64 | public override string ToString()
65 | {
66 | StringBuilder text = new();
67 | text.Append(Head.Name);
68 | text.Append(" ->");
69 | if (Body.Length == 0)
70 | {
71 | text.Append(" ε");
72 | }
73 | else
74 | {
75 | foreach (Symbol item in Body)
76 | {
77 | text.Append(' ');
78 | text.Append(item);
79 | }
80 | }
81 | return text.ToString();
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Compilers/Parsers/ReduceAction.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示 LR 语法分析器的规约动作。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | internal class ReduceAction : Action
8 | where T : struct
9 | {
10 | ///
11 | /// 使用指定的产生式初始化 类的新实例。
12 | ///
13 | /// 规约时用到的产生式。
14 | public ReduceAction(Production production)
15 | {
16 | Production = production;
17 | }
18 |
19 | ///
20 | /// 规约时用到的产生式。
21 | ///
22 | public Production Production { get; }
23 |
24 | ///
25 | /// 获取当前动作是否是成功动作。
26 | ///
27 | public override bool IsSuccessAction => true;
28 |
29 | ///
30 | /// 返回当前动作对应的 。
31 | ///
32 | /// 当前动作对应的 。
33 | public override ParserAction ToParserAction()
34 | {
35 | return ParserAction.Reduce(Production.Index);
36 | }
37 |
38 | ///
39 | /// 返回当前对象是否等于同一类型的另一对象。
40 | ///
41 | /// 要比较的对象。
42 | /// 如果当前对象等于 ,则为 true;否则为 false。
43 | public override bool Equals(Action? other)
44 | {
45 | return other is ReduceAction action && Production == action.Production;
46 | }
47 |
48 | ///
49 | /// 返回当前对象的哈希值。
50 | ///
51 | /// 当前对象的哈希值。
52 | public override int GetHashCode()
53 | {
54 | return Production.GetHashCode();
55 | }
56 |
57 | ///
58 | /// 返回当前对象的字符串表示。
59 | ///
60 | /// 当前对象的字符串表示。
61 | public override string ToString()
62 | {
63 | return $"r{Production.Index}";
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Compilers/Parsers/ShiftAction`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示 LR 语法分析器的移入动作。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | internal class ShiftAction : Action
8 | where T : struct
9 | {
10 | ///
11 | /// 使用指定的状态初始化 类的新实例。
12 | ///
13 | /// 要移入的状态。
14 | public ShiftAction(LRState state)
15 | {
16 | State = state;
17 | }
18 |
19 | ///
20 | /// 要移入的状态。
21 | ///
22 | public LRState State { get; }
23 |
24 | ///
25 | /// 获取当前动作是否是成功动作。
26 | ///
27 | public override bool IsSuccessAction => true;
28 |
29 | ///
30 | /// 返回当前动作对应的 。
31 | ///
32 | /// 当前动作对应的 。
33 | public override ParserAction ToParserAction()
34 | {
35 | return ParserAction.Shift(State.Index);
36 | }
37 |
38 | ///
39 | /// 返回当前对象是否等于同一类型的另一对象。
40 | ///
41 | /// 要比较的对象。
42 | /// 如果当前对象等于 ,则为 true;否则为 false。
43 | public override bool Equals(Action? other)
44 | {
45 | return other is ShiftAction action && State == action.State;
46 | }
47 |
48 | ///
49 | /// 返回当前对象的哈希值。
50 | ///
51 | /// 当前对象的哈希值。
52 | public override int GetHashCode()
53 | {
54 | return State.GetHashCode();
55 | }
56 |
57 | ///
58 | /// 返回当前对象的字符串表示。
59 | ///
60 | /// 当前对象的字符串表示。
61 | public override string ToString()
62 | {
63 | return $"s{State.Index}";
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Compilers/Parsers/StartSymbol`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示起始非终结符。
5 | ///
6 | ///
7 | internal class StartSymbol
8 | where T : struct
9 | {
10 | ///
11 | /// 使用指定的非终结符类型和增广起始符号初始化 类的新实例。
12 | ///
13 | /// 非终结符的类型。
14 | /// 增广起始符号。
15 | /// 分析选项。
16 | public StartSymbol(T kind, Symbol augmentedStartSymbol, ParseOptions option)
17 | {
18 | Kind = kind;
19 | AugmentedStartSymbol = augmentedStartSymbol;
20 | Option = option;
21 | }
22 |
23 | ///
24 | /// 获取非终结符的类型。
25 | ///
26 | public T Kind { get; }
27 | ///
28 | /// 获取增广起始符号。
29 | ///
30 | public Symbol AugmentedStartSymbol { get; }
31 | ///
32 | /// 获取分析选项。
33 | ///
34 | public ParseOptions Option { get; }
35 | }
36 |
--------------------------------------------------------------------------------
/Compilers/Parsers/SymbolStartType.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 符号的起始类型。
5 | ///
6 | internal enum SymbolStartType
7 | {
8 | ///
9 | /// 非起始符号。
10 | ///
11 | NotStart,
12 | ///
13 | /// 起始符号。
14 | ///
15 | Start,
16 | ///
17 | /// 增广起始符号(高接受优先级)。
18 | ///
19 | AugmentedStartHighPriority,
20 | ///
21 | /// 增广起始符号(低接受优先级)。
22 | ///
23 | AugmentedStartLowPriority,
24 | }
25 |
--------------------------------------------------------------------------------
/Compilers/Parsers/SymbolType.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 语法分析中的符号类型。
5 | ///
6 | internal enum SymbolType
7 | {
8 | ///
9 | /// 未知类型。
10 | ///
11 | Unknown,
12 | ///
13 | /// 终结符。
14 | ///
15 | Terminal,
16 | ///
17 | /// 非终结符。
18 | ///
19 | NonTerminal,
20 | ///
21 | /// 错误标记符。
22 | ///
23 | Error,
24 | ///
25 | /// 空串标记符。
26 | ///
27 | Epsilon,
28 | ///
29 | /// 传递标记符。
30 | ///
31 | Spread,
32 | ///
33 | /// 文件结束标记符。
34 | ///
35 | EndOfFile,
36 | }
37 |
--------------------------------------------------------------------------------
/Compilers/Parsers/Symbol`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示语法分析中的符号。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | internal sealed class Symbol
8 | where T : struct
9 | {
10 | ///
11 | /// 文件结束标记符。
12 | ///
13 | public static readonly Symbol EndOfFile = new(GenericConvert.ChangeType(-1), "EOF")
14 | {
15 | Type = SymbolType.EndOfFile
16 | };
17 | ///
18 | /// 错误标记符。
19 | ///
20 | public static readonly Symbol Error = new(GenericConvert.ChangeType(-2), "ERROR")
21 | {
22 | Type = SymbolType.Error
23 | };
24 | ///
25 | /// 空串标记符。
26 | ///
27 | public static readonly Symbol Epsilon = new(GenericConvert.ChangeType(-3), "ε")
28 | {
29 | Type = SymbolType.Epsilon
30 | };
31 | ///
32 | /// 传递标记符。
33 | ///
34 | public static readonly Symbol Spread = new(GenericConvert.ChangeType(-4), "#")
35 | {
36 | Type = SymbolType.Spread
37 | };
38 |
39 | ///
40 | /// 使用指定的符号索引初始化 类的新实例。
41 | ///
42 | /// 符号的类型。
43 | /// 当前符号的名称。
44 | public Symbol(T kind, string name)
45 | {
46 | Index = -1;
47 | Kind = kind;
48 | Name = name;
49 | }
50 |
51 | ///
52 | /// 获取或设置当前符号的索引。
53 | ///
54 | /// 当前符号的索引。
55 | public int Index { get; set; }
56 | ///
57 | /// 获取当前符号的类型。
58 | ///
59 | /// 当前符号的类型。
60 | public T Kind { get; }
61 | ///
62 | /// 获取当前符号的名称。
63 | ///
64 | /// 当前符号的名称索引。
65 | public string Name { get; }
66 | ///
67 | /// 获取或设置当前符号的类型。
68 | ///
69 | public SymbolType Type { get; set; }
70 | ///
71 | /// 获取或设置起始符号类型。
72 | ///
73 | public SymbolStartType StartType { get; set; } = SymbolStartType.NotStart;
74 | ///
75 | /// 获取当前非终结符的所有产生式。
76 | ///
77 | /// 当前非终结符的所有产生式。
78 | public List> Productions { get; } = new();
79 |
80 | ///
81 | /// 返回当前对象的字符串表示形式。
82 | ///
83 | /// 当前对象的字符串表示形式。
84 | public override string ToString()
85 | {
86 | return Name;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Compilers/RegularExpressions/EndOfFileExp.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace Cyjb.Compilers.RegularExpressions;
4 |
5 | ///
6 | /// 表示文件结束的正则表达式,只能用于先前看表达式中。
7 | ///
8 | public sealed class EndOfFileExp : LexRegex
9 | {
10 | ///
11 | /// 初始化 类的新实例。
12 | ///
13 | internal EndOfFileExp() { }
14 |
15 | ///
16 | /// 获取当前正则表达式匹配的字符串长度。
17 | ///
18 | /// 当前正则表达式匹配的字符串长度。如果可以匹配不同长度的字符串,则为 null。
19 | public override int? Length => 0;
20 |
21 | ///
22 | /// 返回当前对象是否等于同一类型的另一对象。
23 | ///
24 | /// 要比较的对象。
25 | /// 如果当前对象等于 ,则为 true;否则为 false。
26 | public override bool Equals(LexRegex? other)
27 | {
28 | return (other is EndOfFileExp);
29 | }
30 |
31 | ///
32 | /// 返回当前对象的哈希值。
33 | ///
34 | /// 当前对象的哈希值。
35 | public override int GetHashCode()
36 | {
37 | return typeof(EndOfFileExp).GetHashCode();
38 | }
39 |
40 | ///
41 | /// 返回当前对象的字符串表示形式。
42 | ///
43 | /// 字符串构造器。
44 | internal override void ToString(StringBuilder builder)
45 | {
46 | builder.Append("{EOF}");
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Compilers/Resources.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Compilers/Resources.cs
--------------------------------------------------------------------------------
/Compilers/Resources.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="$(PkgCyjb)\content\ResourcesTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/Design/CompilerTemplate.t4:
--------------------------------------------------------------------------------
1 | <#
2 | /**
3 | * 生成词法分析器或语法分析器的实现。
4 | */
5 | #>
6 | <#@ template language="C#" hostspecific="true" #>
7 | <#@output extension=".designed.cs" encoding="UTF-8"#>
8 | <#@ assembly name="System.Core" #>
9 | <#@ assembly name="System.Runtime" #>
10 | <#@ assembly name="EnvDTE" #>
11 | <#@ assembly name="VSLangProj" #>
12 | <#@ import namespace="EnvDTE" #>
13 | <#@ import namespace="System" #>
14 | <#@ import namespace="System.CodeDom.Compiler" #>
15 | <#@ import namespace="System.Diagnostics" #>
16 | <#@ import namespace="System.IO" #>
17 | <#@ import namespace="System.Text.RegularExpressions" #>
18 | <#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
19 | <#
20 | string toolPath = Host.ResolveAssemblyReference(@"$(PkgCyjb_Compilers_Design)\Tools\Generator.dll");
21 | string filePath = Host.TemplateFile.Replace(".tt", ".cs");
22 | try
23 | {
24 | using System.Diagnostics.Process myProcess = new();
25 | myProcess.StartInfo.UseShellExecute = false;
26 | myProcess.StartInfo.RedirectStandardOutput = true;
27 | myProcess.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;
28 | myProcess.StartInfo.FileName = "dotnet";
29 | myProcess.StartInfo.Arguments = $"\"{Path.GetFullPath(toolPath)}\" \"{Path.GetFullPath(filePath)}\"";
30 | myProcess.StartInfo.CreateNoWindow = true;
31 | myProcess.Start();
32 | string content = myProcess.StandardOutput.ReadToEnd();
33 | myProcess.WaitForExit();
34 |
35 | if (content.StartsWith(Path.GetFileName(filePath)))
36 | {
37 | // 包含异常
38 | string[] lines = content.Trim().Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
39 | Regex errorRegex = new Regex(@"^.+\((\d+),(\d+)\): (.+)$");
40 | foreach(string line in lines)
41 | {
42 | Match match = errorRegex.Match(line);
43 | if (match.Success) {
44 | string lineNum = match.Groups[1].Captures[0].Value;
45 | string colNum = match.Groups[2].Captures[0].Value;
46 | string message = match.Groups[3].Captures[0].Value;
47 | Errors.Add(new CompilerError(filePath, int.Parse(lineNum), int.Parse(colNum), "", message));
48 | }
49 | }
50 | Write("// 生成异常");
51 | } else {
52 | Write(content);
53 | }
54 | }
55 | catch (Exception e)
56 | {
57 | Error($"执行 {toolPath} 失败:{e.Message}");
58 | }
59 | #>
60 |
61 |
--------------------------------------------------------------------------------
/Design/Cyjb.Compilers.Design.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | enable
5 | enable
6 | False
7 | True
8 | https://github.com/CYJB/Cyjb.Compilers
9 | 提供编译器的设计时生成功能
10 | Copyright (c) 2022, CYJB
11 | README.md
12 | LICENSE.txt
13 | en
14 | $(VersionPrefix)
15 | 1.0.23
16 | Cyjb.Compilers
17 | Library
18 | true
19 | CYJB
20 | Compiler, T4
21 |
22 |
23 | ../CYJB_Code_Key.snk
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | $(DefineConstants);DEBUG
32 |
33 |
34 |
35 | true
36 | true
37 | tools\
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Design/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013, CYJB
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice, this
11 | list of conditions and the following disclaimer in the documentation and/or
12 | other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/Design/Lexers/LexerContextAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace Cyjb.Compilers.Lexers;
4 |
5 | ///
6 | /// 表示词法分析器的上下文。
7 | ///
8 | [Conditional("DEBUG")]
9 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
10 | public sealed class LexerContextAttribute : Attribute
11 | {
12 |
13 | #pragma warning disable IDE0060 // 删除未使用的参数
14 |
15 | ///
16 | /// 使用指定的上下文标签初始化 类的新实例。
17 | ///
18 | /// 上下文的标签。
19 | public LexerContextAttribute(string label) { }
20 |
21 | #pragma warning restore IDE0060 // 删除未使用的参数
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Design/Lexers/LexerInclusiveContextAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace Cyjb.Compilers.Lexers;
4 |
5 | ///
6 | /// 表示词法分析器的包含型上下文。
7 | ///
8 | [Conditional("DEBUG")]
9 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
10 | public sealed class LexerInclusiveContextAttribute : Attribute
11 | {
12 |
13 | #pragma warning disable IDE0060 // 删除未使用的参数
14 |
15 | ///
16 | /// 使用指定的上下文标签初始化 类的新实例。
17 | ///
18 | /// 上下文的标签。
19 | public LexerInclusiveContextAttribute(string label) { }
20 |
21 | #pragma warning restore IDE0060 // 删除未使用的参数
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Design/Lexers/LexerRegexAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Text.RegularExpressions;
3 |
4 | namespace Cyjb.Compilers.Lexers;
5 |
6 | ///
7 | /// 表示词法分析的正则表达式定义。
8 | ///
9 | [Conditional("DEBUG")]
10 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
11 | public sealed class LexerRegexAttribute : Attribute
12 | {
13 |
14 | #pragma warning disable IDE0060 // 删除未使用的参数
15 |
16 | ///
17 | /// 使用指定的正则表达式信息初始化 类的新实例。
18 | ///
19 | /// 正则表达式的名称。
20 | /// 定义的正则表达式。
21 | /// 正则表达式的选项。
22 | public LexerRegexAttribute(string name, string regex, RegexOptions options = RegexOptions.None) { }
23 |
24 | #pragma warning restore IDE0060 // 删除未使用的参数
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/Design/Lexers/LexerRejectableAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace Cyjb.Compilers.Lexers;
4 |
5 | ///
6 | /// 表示词法分析是否用到了 Reject 动作。
7 | ///
8 | [Conditional("DEBUG")]
9 | [AttributeUsage(AttributeTargets.Class)]
10 | public sealed class LexerRejectableAttribute : Attribute
11 | {
12 | ///
13 | /// 初始化 类的新实例。
14 | ///
15 | public LexerRejectableAttribute() { }
16 | }
17 |
--------------------------------------------------------------------------------
/Design/Lexers/LexerSymbolAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Text.RegularExpressions;
3 |
4 | namespace Cyjb.Compilers.Lexers;
5 |
6 | ///
7 | /// 表示词法分析的终结符定义。
8 | ///
9 | [Conditional("DEBUG")]
10 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
11 | public sealed class LexerSymbolAttribute : Attribute
12 | {
13 |
14 | #pragma warning disable IDE0060 // 删除未使用的参数
15 |
16 | ///
17 | /// 使用指定的终结符信息初始化 类的新实例。
18 | ///
19 | /// 终结符的正则表达式。
20 | /// 正则表达式的选项。
21 | public LexerSymbolAttribute(string regex, RegexOptions options = RegexOptions.None) { }
22 |
23 | #pragma warning restore IDE0060 // 删除未使用的参数
24 |
25 | ///
26 | /// 获取或设置终结符的词法单元类型。
27 | ///
28 | public object? Kind { get; set; }
29 |
30 | ///
31 | /// 获取或设置终结符的词法单元值。
32 | ///
33 | public object? Value { get; set; }
34 |
35 | ///
36 | /// 获取或设置是否使用终结符的最短匹配。
37 | ///
38 | /// 默认都会使用正则表达式的最长匹配,允许指定为使用最短匹配,
39 | /// 会在遇到第一个匹配时立即返回结果。
40 | public bool UseShortest { get; set; }
41 | }
42 |
--------------------------------------------------------------------------------
/Design/Parsers/ParserLeftAssociateAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace Cyjb.Compilers.Parsers;
4 |
5 | ///
6 | /// 表示语法分析器的左结合符号。
7 | ///
8 | [Conditional("DEBUG")]
9 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
10 | public sealed class ParserLeftAssociateAttribute : Attribute
11 | {
12 |
13 | #pragma warning disable IDE0060 // 删除未使用的参数
14 |
15 | ///
16 | /// 使用指定的左结合符号初始化 类的新实例。
17 | ///
18 | /// 左结合符号。
19 | public ParserLeftAssociateAttribute(params object[] kinds) { }
20 |
21 | #pragma warning restore IDE0060 // 删除未使用的参数
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Design/Parsers/ParserNonAssociateAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace Cyjb.Compilers.Parsers;
4 |
5 | ///
6 | /// 表示语法分析器的非结合符号。
7 | ///
8 | [Conditional("DEBUG")]
9 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
10 | public sealed class ParserNonAssociateAttribute : Attribute
11 | {
12 |
13 | #pragma warning disable IDE0060 // 删除未使用的参数
14 |
15 | ///
16 | /// 使用指定的非结合符号初始化 类的新实例。
17 | ///
18 | /// 非结合符号。
19 | public ParserNonAssociateAttribute(params object[] kinds) { }
20 |
21 | #pragma warning restore IDE0060 // 删除未使用的参数
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Design/Parsers/ParserProductionAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace Cyjb.Compilers.Parsers;
4 |
5 | ///
6 | /// 表示语法分析器的产生式。
7 | ///
8 | [Conditional("DEBUG")]
9 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
10 | public sealed class ParserProductionAttribute : Attribute
11 | {
12 |
13 | #pragma warning disable IDE0060 // 删除未使用的参数
14 |
15 | ///
16 | /// 使用指定的产生式所属的非终结符和内容初始化 类的新实例。
17 | ///
18 | /// 产生式所属的非终结符。
19 | /// 产生式的内容。
20 | public ParserProductionAttribute(object kind, params object[] body) { }
21 |
22 | #pragma warning restore IDE0060 // 删除未使用的参数
23 |
24 | ///
25 | /// 获取或设置设置当前产生式的优先级与指定的非终结符相同。
26 | ///
27 | public object? Prec { get; set; }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/Design/Parsers/ParserRightAssociateAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace Cyjb.Compilers.Parsers;
4 |
5 | ///
6 | /// 表示语法分析器的右结合符号。
7 | ///
8 | [Conditional("DEBUG")]
9 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
10 | public sealed class ParserRightAssociateAttribute : Attribute
11 | {
12 |
13 | #pragma warning disable IDE0060 // 删除未使用的参数
14 |
15 | ///
16 | /// 使用指定的右结合符号初始化 类的新实例。
17 | ///
18 | /// 右结合符号。
19 | public ParserRightAssociateAttribute(params object[] kinds) { }
20 |
21 | #pragma warning restore IDE0060 // 删除未使用的参数
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Design/Parsers/ParserStartAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace Cyjb.Compilers.Parsers;
4 |
5 | ///
6 | /// 表示语法分析器的起始符号。
7 | ///
8 | [Conditional("DEBUG")]
9 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
10 | public sealed class ParserStartAttribute : Attribute
11 | {
12 |
13 | #pragma warning disable IDE0060 // 删除未使用的参数
14 |
15 | ///
16 | /// 使用指定的起始符号初始化 类的新实例。
17 | ///
18 | /// 语法分析器的起始符号。
19 | public ParserStartAttribute(object kind) { }
20 |
21 | ///
22 | /// 使用指定的起始符号和分析选项初始化 类的新实例。
23 | ///
24 | /// 语法分析器的起始符号。
25 | /// 语法分析器的分析选项。
26 | public ParserStartAttribute(object kind, ParseOptions option) { }
27 |
28 | #pragma warning restore IDE0060 // 删除未使用的参数
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/Design/Tools/Cyjb.Compilers.Design.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/Cyjb.Compilers.Design.dll
--------------------------------------------------------------------------------
/Design/Tools/Cyjb.Compilers.Runtime.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/Cyjb.Compilers.Runtime.dll
--------------------------------------------------------------------------------
/Design/Tools/Cyjb.Compilers.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/Cyjb.Compilers.dll
--------------------------------------------------------------------------------
/Design/Tools/Cyjb.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/Cyjb.dll
--------------------------------------------------------------------------------
/Design/Tools/Generator.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/Generator.dll
--------------------------------------------------------------------------------
/Design/Tools/Generator.runtimeconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "runtimeOptions": {
3 | "tfm": "net6.0",
4 | "framework": {
5 | "name": "Microsoft.NETCore.App",
6 | "version": "6.0.0"
7 | },
8 | "configProperties": {
9 | "System.Reflection.Metadata.MetadataUpdater.IsSupported": false
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/Design/Tools/Microsoft.CodeAnalysis.CSharp.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/Microsoft.CodeAnalysis.CSharp.dll
--------------------------------------------------------------------------------
/Design/Tools/Microsoft.CodeAnalysis.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/Microsoft.CodeAnalysis.dll
--------------------------------------------------------------------------------
/Design/Tools/System.Collections.Immutable.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/System.Collections.Immutable.dll
--------------------------------------------------------------------------------
/Design/Tools/System.Reflection.Metadata.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/System.Reflection.Metadata.dll
--------------------------------------------------------------------------------
/Design/Tools/zh-Hans/Cyjb.Compilers.Runtime.resources.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/zh-Hans/Cyjb.Compilers.Runtime.resources.dll
--------------------------------------------------------------------------------
/Design/Tools/zh-Hans/Cyjb.Compilers.resources.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/zh-Hans/Cyjb.Compilers.resources.dll
--------------------------------------------------------------------------------
/Design/Tools/zh-Hans/Cyjb.resources.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/zh-Hans/Cyjb.resources.dll
--------------------------------------------------------------------------------
/Design/Tools/zh-Hans/Generator.resources.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/zh-Hans/Generator.resources.dll
--------------------------------------------------------------------------------
/Design/Tools/zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll
--------------------------------------------------------------------------------
/Design/Tools/zh-Hans/Microsoft.CodeAnalysis.resources.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Design/Tools/zh-Hans/Microsoft.CodeAnalysis.resources.dll
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/AttributeArguments.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp.Syntax;
2 |
3 | namespace Cyjb.CodeAnalysis.CSharp;
4 |
5 | ///
6 | /// 特性的参数信息。
7 | ///
8 | internal class AttributeArguments
9 | {
10 | ///
11 | /// 参数值的字典。
12 | ///
13 | private readonly Dictionary arguments;
14 |
15 | ///
16 | /// 使用特性的参数信息初始化 类的新实例。
17 | ///
18 | /// 参数值的字典。
19 | /// params 参数值。
20 | public AttributeArguments(Dictionary arguments, ExpressionSyntax[] paramsArgument)
21 | {
22 | this.arguments = arguments;
23 | ParamsArgument = paramsArgument;
24 | }
25 |
26 | ///
27 | /// 获取指定名称参数的值。
28 | ///
29 | /// 要获取值的参数名称。
30 | /// 指定名称参数的值,如果不存在则返回 null。
31 | public ExpressionSyntax? this[string name]
32 | {
33 | get
34 | {
35 | if (arguments.TryGetValue(name, out var value))
36 | {
37 | return value;
38 | }
39 | return null;
40 | }
41 | }
42 |
43 | ///
44 | /// params 参数的值。
45 | ///
46 | public ExpressionSyntax[] ParamsArgument { get; }
47 | }
48 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/AttributeParameterInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using Cyjb.Reflection;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 特性的参数信息。
8 | ///
9 | internal struct AttributeParameterInfo
10 | {
11 | ///
12 | /// 参数名称。
13 | ///
14 | public string Name;
15 | ///
16 | /// 是否是可选参数。
17 | ///
18 | public bool IsOptional;
19 | ///
20 | /// 是否是 params 参数。
21 | ///
22 | public bool IsParamArray;
23 |
24 | ///
25 | /// 使用指定的 初始化。
26 | ///
27 | /// 参数信息。
28 | public AttributeParameterInfo(ParameterInfo param)
29 | {
30 | Name = param.Name!;
31 | IsOptional = param.IsOptional;
32 | IsParamArray = param.IsParamArray();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/AttributeSyntaxUtil.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 提供 相关的扩展方法。
8 | ///
9 | internal static class AttributeSyntaxUtil
10 | {
11 | ///
12 | /// 返回当前特性列表中的所有特性。
13 | ///
14 | /// 特性列表。
15 | /// 特性列表中包含的每个特性。
16 | public static IEnumerable GetAttributes(this SyntaxList attrList)
17 | {
18 | foreach (AttributeListSyntax list in attrList)
19 | {
20 | foreach (AttributeSyntax attr in list.Attributes)
21 | {
22 | yield return attr;
23 | }
24 | }
25 | }
26 |
27 | ///
28 | /// 返回当前特性的完整名称(包含 Attribute 后缀)。
29 | ///
30 | /// 要检查的特性。
31 | /// 特性的完整名称。
32 | public static string GetFullName(this AttributeSyntax attr)
33 | {
34 | if (attr.Name is NameSyntax nameSyntax)
35 | {
36 | string name = nameSyntax.GetSimpleName().ToString();
37 | if (!name.EndsWith("Attribute"))
38 | {
39 | name += "Attribute";
40 | }
41 | return name;
42 | }
43 | else
44 | {
45 | // 在正确的语法里,特性好像不太走到这里。
46 | return attr.Name.ToString();
47 | }
48 | }
49 |
50 | ///
51 | /// 返回当前特性的参数列表。
52 | ///
53 | /// 要解析的特性。
54 | /// 特性的模型。
55 | /// 特性参数。
56 | /// 未能正确解析特性参数。
57 | public static AttributeArguments GetArguments(this AttributeSyntax attr, AttributeModel model)
58 | {
59 | return model.GetArguments(attr);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/ArgumentBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.CodeAnalysis.CSharp;
6 |
7 | ///
8 | /// 实参的构造器。
9 | ///
10 | internal sealed class ArgumentBuilder
11 | {
12 | ///
13 | /// 参数的表达式。
14 | ///
15 | private readonly ExpressionBuilder expression;
16 | ///
17 | /// 参数的名称。
18 | ///
19 | private string? name;
20 | ///
21 | /// 参数引用的类型。
22 | ///
23 | private SyntaxKind refKind = SyntaxKind.None;
24 |
25 | ///
26 | /// 使用指定的表达式初始化 类的新实例。
27 | ///
28 | /// 参数的表达式。
29 | public ArgumentBuilder(ExpressionBuilder expression)
30 | {
31 | this.expression = expression;
32 | }
33 |
34 | ///
35 | /// 设置参数的名称。
36 | ///
37 | /// 参数的名称。
38 | /// 当前方法实参的构造器。
39 | public ArgumentBuilder Name(string name)
40 | {
41 | this.name = name;
42 | return this;
43 | }
44 |
45 | ///
46 | /// 设置参数的引用。
47 | ///
48 | /// 参数的引用。
49 | /// 当前方法实参的构造器。
50 | public ArgumentBuilder Ref(SyntaxKind kind)
51 | {
52 | refKind = kind;
53 | return this;
54 | }
55 |
56 | ///
57 | /// 构造实参语法节点。
58 | ///
59 | /// 语法的格式信息。
60 | /// 实参语法节点。
61 | public ArgumentSyntax GetSyntax(SyntaxFormat format)
62 | {
63 | ArgumentSyntax syntax = SyntaxFactory.Argument(expression.GetSyntax(format));
64 | if (name != null)
65 | {
66 | syntax = syntax.WithNameColon(SyntaxFactory.NameColon(name)
67 | .WithTrailingTrivia(SyntaxFactory.Space));
68 | }
69 | if (refKind != SyntaxKind.None)
70 | {
71 | syntax = syntax.WithRefKindKeyword(SyntaxFactory.Token(refKind)
72 | .WithTrailingTrivia(SyntaxFactory.Space));
73 | }
74 | return syntax;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/AttributeArgumentBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.CodeAnalysis.CSharp;
6 |
7 | ///
8 | /// 特性参数的构造器。
9 | ///
10 | internal sealed class AttributeArgumentBuilder
11 | {
12 | ///
13 | /// 参数的表达式。
14 | ///
15 | private readonly ExpressionBuilder expression;
16 | ///
17 | /// 参数的名称。
18 | ///
19 | private string? name;
20 | ///
21 | /// 参数是否是特性成员。
22 | ///
23 | private bool isMember = false;
24 |
25 | ///
26 | /// 使用指定的表达式初始化 类的新实例。
27 | ///
28 | /// 参数的表达式。
29 | public AttributeArgumentBuilder(ExpressionBuilder expression)
30 | {
31 | this.expression = expression;
32 | }
33 |
34 | ///
35 | /// 设置参数的名称。
36 | ///
37 | /// 参数的名称。
38 | /// 参数是否是特性成员。
39 | /// 当前特性参数的构造器。
40 | public AttributeArgumentBuilder Name(string name, bool isMember = false)
41 | {
42 | this.name = name;
43 | this.isMember = isMember;
44 | return this;
45 | }
46 |
47 | ///
48 | /// 构造特性参数语法节点。
49 | ///
50 | /// 语法的格式信息。
51 | /// 特性参数语法节点。
52 | public AttributeArgumentSyntax GetSyntax(SyntaxFormat format)
53 | {
54 | var syntax = SyntaxFactory.AttributeArgument(expression.GetSyntax(format));
55 | if (name != null)
56 | {
57 | if (isMember)
58 | {
59 | syntax = syntax.WithNameEquals(SyntaxFactory.NameEquals(name)
60 | .WithLeadingTrivia(SyntaxFactory.Space)
61 | .WithTrailingTrivia(SyntaxFactory.Space));
62 | }
63 | else
64 | {
65 | syntax = syntax.WithNameColon(SyntaxFactory.NameColon(name)
66 | .WithTrailingTrivia(SyntaxFactory.Space));
67 | }
68 | }
69 | return syntax;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/AttributeArgumentListBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 特性参数列表的构造器。
8 | ///
9 | internal sealed class AttributeArgumentListBuilder
10 | {
11 | ///
12 | /// 特性参数列表。
13 | ///
14 | private readonly List AttributeArguments = new();
15 | ///
16 | /// 特性参数的换行信息,0 表示不换行。
17 | ///
18 | private int wrap = 0;
19 |
20 | ///
21 | /// 参数的个数。
22 | ///
23 | public int Count => AttributeArguments.Count;
24 |
25 | ///
26 | /// 添加指定的特性参数。
27 | ///
28 | /// 参数表达式。
29 | /// 当前特性参数列表构造器。
30 | public AttributeArgumentListBuilder Add(ExpressionBuilder expression)
31 | {
32 | AttributeArguments.Add(new AttributeArgumentBuilder(expression));
33 | return this;
34 | }
35 |
36 | ///
37 | /// 添加指定的特性参数。
38 | ///
39 | /// 参数表达式。
40 | /// 参数的名称。
41 | /// 参数是否是特性成员。
42 | /// 当前特性参数列表构造器。
43 | public AttributeArgumentListBuilder Add(ExpressionBuilder expression, string name, bool isMember = false)
44 | {
45 | AttributeArguments.Add(new AttributeArgumentBuilder(expression).Name(name, isMember));
46 | return this;
47 | }
48 |
49 | ///
50 | /// 设置参数的换行情况,默认为 0 表示不换行。
51 | ///
52 | /// 换行情况。
53 | /// 当前特性参数列表构造器。
54 | public AttributeArgumentListBuilder Wrap(int wrap)
55 | {
56 | if (wrap >= 0)
57 | {
58 | this.wrap = wrap;
59 | }
60 | return this;
61 | }
62 |
63 | ///
64 | /// 构造特性参数的列表。
65 | ///
66 | /// 语法的格式信息。
67 | /// 特性参数列表。
68 | public AttributeArgumentListSyntax GetSyntax(SyntaxFormat format)
69 | {
70 | return SyntaxFactory.AttributeArgumentList(SyntaxBuilder.SeparatedList(
71 | AttributeArguments.Select(arg => arg.GetSyntax(format)), format.IncDepth(), wrap));
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/AttributeBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 特性构造器。
8 | ///
9 | internal sealed class AttributeBuilder
10 | {
11 | ///
12 | /// 特性的名称。
13 | ///
14 | private readonly NameBuilder name;
15 | ///
16 | /// 特性的参数。
17 | ///
18 | private readonly AttributeArgumentListBuilder arguments = new();
19 |
20 | ///
21 | /// 使用指定的名称初始化 类的新实例。
22 | ///
23 | /// 特性的名称。
24 | public AttributeBuilder(NameBuilder name)
25 | {
26 | this.name = name;
27 | }
28 |
29 | ///
30 | /// 添加特性的参数。
31 | ///
32 | /// 特性的参数。
33 | /// 当前特性构造器。
34 | public AttributeBuilder Argument(ExpressionBuilder argument)
35 | {
36 | arguments.Add(argument);
37 | return this;
38 | }
39 |
40 | ///
41 | /// 添加特性的参数。
42 | ///
43 | /// 特性的参数。
44 | /// 参数的名称。
45 | /// 参数是否是特性成员。
46 | /// 当前特性构造器。
47 | public AttributeBuilder Argument(ExpressionBuilder argument, string name, bool isMember = false)
48 | {
49 | arguments.Add(argument, name, isMember);
50 | return this;
51 | }
52 |
53 | ///
54 | /// 构造特性语法节点。
55 | ///
56 | /// 语法的格式信息。
57 | /// 特性语法节点。
58 | public AttributeSyntax GetSyntax(SyntaxFormat format)
59 | {
60 | var syntax = SyntaxFactory.Attribute(name.GetSyntax(format));
61 | if (arguments.Count > 0)
62 | {
63 | syntax = syntax.WithArgumentList(arguments.GetSyntax(format));
64 | }
65 | return syntax;
66 | }
67 |
68 | ///
69 | /// 构造特性列表语法节点。
70 | ///
71 | /// 语法的格式信息。
72 | /// 特性列表语法节点。
73 | public AttributeListSyntax GetListSyntax(SyntaxFormat format)
74 | {
75 | return SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(GetSyntax(format)));
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Declarations/BaseMethodDeclarationBuilder.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.CodeAnalysis.CSharp;
2 |
3 | ///
4 | /// 方法声明的基构造器。
5 | ///
6 | internal abstract class BaseMethodDeclarationBuilder : MemberDeclarationBuilder
7 | {
8 | ///
9 | /// 方法的参数列表。
10 | ///
11 | internal protected readonly ParameterListBuilder parameters = new();
12 | ///
13 | /// 方法体构造器。
14 | ///
15 | internal protected BlockBuilder? block;
16 | }
17 |
18 | ///
19 | /// 提供方法声明基构造器的辅助功能。
20 | ///
21 | internal static class BaseMethodDeclarationBuilderUtil
22 | {
23 | ///
24 | /// 添加方法声明的参数。
25 | ///
26 | /// 方法声明的类型。
27 | /// 参数的名称。
28 | /// 参数的类型。
29 | /// 当前方法声明构造器。
30 | public static T Parameter(this T builder, string name, TypeBuilder type)
31 | where T : BaseMethodDeclarationBuilder
32 | {
33 | builder.parameters.Add(name, type);
34 | return builder;
35 | }
36 |
37 | ///
38 | /// 添加方法体的语句。
39 | ///
40 | /// 方法声明的类型。
41 | /// 语句。
42 | /// 当前方法声明构造器。
43 | public static T Statement(this T builder, StatementBuilder? statement)
44 | where T : BaseMethodDeclarationBuilder
45 | {
46 | if (statement != null)
47 | {
48 | builder.block ??= new BlockBuilder();
49 | builder.block.Add(statement);
50 | }
51 | return builder;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Declarations/MethodDeclarationBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.CodeAnalysis.CSharp;
6 |
7 | ///
8 | /// 方法声明的构造器。
9 | ///
10 | internal sealed class MethodDeclarationBuilder : BaseMethodDeclarationBuilder
11 | {
12 | ///
13 | /// 方法的返回值。
14 | ///
15 | private readonly TypeBuilder returnType;
16 | ///
17 | /// 方法的名称。
18 | ///
19 | private readonly string methodName;
20 |
21 | ///
22 | /// 使用指定的方法返回类型和名称初始化 类的新实例。
23 | ///
24 | /// 方法的返回类型。
25 | /// 方法的名称。
26 | public MethodDeclarationBuilder(TypeBuilder returnType, string methodName)
27 | {
28 | this.returnType = returnType;
29 | this.methodName = methodName;
30 | }
31 |
32 | ///
33 | /// 构造方法声明语法节点。
34 | ///
35 | /// 语法的格式信息。
36 | /// 方法声明语法节点。
37 | public override MethodDeclarationSyntax GetSyntax(SyntaxFormat format)
38 | {
39 | SyntaxList attributeLists = attributes.GetSyntax(format);
40 | SyntaxTokenList modifiers = this.modifiers.GetSyntax(format);
41 | var returnType = this.returnType.GetSyntax(format)
42 | .WithLeadingTrivia(this.modifiers.Count > 0 ? SyntaxFactory.Space : format.Indentation);
43 | var identifier = SyntaxFactory.Identifier(methodName).WithLeadingTrivia(SyntaxFactory.Space);
44 | ParameterListSyntax parameterList = parameters.GetSyntax(format);
45 | BlockSyntax? body = null;
46 | if (block != null)
47 | {
48 | body = block.GetSyntax(format)
49 | .WithLeadingTrivia(format.EndOfLine, format.Indentation)
50 | .WithTrailingTrivia(format.EndOfLine);
51 | }
52 |
53 | MethodDeclarationSyntax syntax = SyntaxFactory.MethodDeclaration(
54 | attributeLists, modifiers, returnType, null, identifier, null,
55 | parameterList, SyntaxFactory.List(),
56 | body, null
57 | );
58 | if (commentBuilder.HasComment)
59 | {
60 | syntax = syntax.InsertLeadingTrivia(0, SyntaxFactory.Trivia(commentBuilder.GetSyntax(format)));
61 | }
62 | return syntax;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Expressions/AssignmentExpressionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.CodeAnalysis.CSharp;
6 |
7 | ///
8 | /// 赋值表达式的构造器。
9 | ///
10 | internal class AssignmentExpressionBuilder : ExpressionBuilder
11 | {
12 | ///
13 | /// 赋值表达式的类型。
14 | ///
15 | private readonly SyntaxKind kind;
16 | ///
17 | /// 赋值表达式左侧的表达式。
18 | ///
19 | private readonly ExpressionBuilder left;
20 | ///
21 | /// 赋值表达式右侧的表达式。
22 | ///
23 | private readonly ExpressionBuilder right;
24 |
25 | ///
26 | /// 使用指定的表达式初始化 类的新实例。
27 | ///
28 | /// 表达式的类型。
29 | /// 左侧的表达式。
30 | /// 右侧的表达式。
31 | public AssignmentExpressionBuilder(SyntaxKind kind, ExpressionBuilder left, ExpressionBuilder right)
32 | {
33 | this.kind = kind;
34 | this.left = left;
35 | this.right = right;
36 | }
37 |
38 | ///
39 | /// 构造赋值表达式。
40 | ///
41 | /// 语法的格式信息。
42 | /// 赋值表达式。
43 | public override AssignmentExpressionSyntax GetSyntax(SyntaxFormat format)
44 | {
45 | return SyntaxFactory.AssignmentExpression(kind,
46 | left.GetSyntax(format).WithTrailingTrivia(SyntaxFactory.Space),
47 | right.GetSyntax(format).WithLeadingTrivia(SyntaxFactory.Space));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Expressions/BinaryExpressionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.CSharp;
4 | using Microsoft.CodeAnalysis.CSharp.Syntax;
5 |
6 | namespace Cyjb.Compilers.CodeAnalysis;
7 |
8 | ///
9 | /// 二元表达式的构造器。
10 | ///
11 | internal class BinaryExpressionBuilder : ExpressionBuilder
12 | {
13 | ///
14 | /// 二元表达式的类型。
15 | ///
16 | private readonly SyntaxKind kind;
17 | ///
18 | /// 二元表达式左侧的表达式。
19 | ///
20 | private readonly ExpressionBuilder left;
21 | ///
22 | /// 二元表达式右侧的表达式。
23 | ///
24 | private readonly ExpressionBuilder right;
25 |
26 | ///
27 | /// 使用指定的表达式初始化 类的新实例。
28 | ///
29 | /// 表达式的类型。
30 | /// 左侧的表达式。
31 | /// 右侧的表达式。
32 | public BinaryExpressionBuilder(SyntaxKind kind, ExpressionBuilder left, ExpressionBuilder right)
33 | {
34 | this.kind = kind;
35 | this.left = left;
36 | this.right = right;
37 | }
38 |
39 | ///
40 | /// 构造二元表达式。
41 | ///
42 | /// 语法的格式信息。
43 | /// 二元表达式。
44 | public override BinaryExpressionSyntax GetSyntax(SyntaxFormat format)
45 | {
46 | return SyntaxFactory.BinaryExpression(kind,
47 | left.GetSyntax(format).WithTrailingTrivia(SyntaxFactory.Space),
48 | right.GetSyntax(format).WithLeadingTrivia(SyntaxFactory.Space));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Expressions/CastExpressionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 强制类型转换表达式构造器。
8 | ///
9 | internal class CastExpressionBuilder : ExpressionBuilder
10 | {
11 | ///
12 | /// 要转换到的类型。
13 | ///
14 | private readonly TypeBuilder type;
15 | ///
16 | /// 要转换的表达式。
17 | ///
18 | private readonly ExpressionBuilder expression;
19 |
20 | ///
21 | /// 使用指定的类型和表达式初始化 类的新实例。
22 | ///
23 | /// 要转换到的类型。
24 | /// 要转换的表达式。
25 | public CastExpressionBuilder(TypeBuilder type, ExpressionBuilder expression)
26 | {
27 | this.type = type;
28 | this.expression = expression;
29 | }
30 |
31 | ///
32 | /// 构造强制类型转换表达式。
33 | ///
34 | /// 语法的格式信息。
35 | /// 强制类型转换表达式。
36 | public override CastExpressionSyntax GetSyntax(SyntaxFormat format)
37 | {
38 | return SyntaxFactory.CastExpression(type.GetSyntax(format), expression.GetSyntax(format));
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Expressions/ElementAccessExpressionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 元素访问表达式的构造器。
8 | ///
9 | internal class ElementAccessExpressionBuilder : ExpressionBuilder
10 | {
11 | ///
12 | /// 要访问元素的表达式。
13 | ///
14 | private readonly ExpressionBuilder expression;
15 | ///
16 | /// 要访问的元素。
17 | ///
18 | private readonly List arguments = new();
19 |
20 | ///
21 | /// 使用指定的表达式初始化 类的新实例。
22 | ///
23 | /// 要访问元素的表达式。
24 | public ElementAccessExpressionBuilder(ExpressionBuilder expression)
25 | {
26 | this.expression = expression;
27 | }
28 |
29 | ///
30 | /// 添加指定的元素参数。
31 | ///
32 | /// 参数表达式。
33 | /// 当前元素访问表达式的构造器。
34 | public ElementAccessExpressionBuilder Argument(ExpressionBuilder expression)
35 | {
36 | arguments.Add(new ArgumentBuilder(expression));
37 | return this;
38 | }
39 |
40 | ///
41 | /// 构造元素访问表达式。
42 | ///
43 | /// 语法的格式信息。
44 | /// 元素访问表达式语法节点。
45 | public override ElementAccessExpressionSyntax GetSyntax(SyntaxFormat format)
46 | {
47 | return SyntaxFactory.ElementAccessExpression(expression.GetSyntax(format),
48 | SyntaxFactory.BracketedArgumentList(SyntaxBuilder.SeparatedList(
49 | arguments.Select(arg => arg.GetSyntax(format)), format.IncDepth(), 0)));
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Expressions/InvocationExpressionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 方法调用表达式的构造器。
8 | ///
9 | internal sealed class InvocationExpressionBuilder : ExpressionBuilder
10 | {
11 | ///
12 | /// 要调用的方法。
13 | ///
14 | private readonly ExpressionBuilder expression;
15 | ///
16 | /// 方法的调用参数。
17 | ///
18 | private readonly ArgumentListBuilder arguments = new();
19 |
20 | ///
21 | /// 使用要调用的方法表达式初始化 类的新实例。
22 | ///
23 | /// 要调用的方法。
24 | public InvocationExpressionBuilder(ExpressionBuilder expression)
25 | {
26 | this.expression = expression;
27 | }
28 |
29 | ///
30 | /// 添加方法的参数。
31 | ///
32 | /// 方法的参数。
33 | /// 当前方法调用表达式构造器。
34 | public InvocationExpressionBuilder Argument(ExpressionBuilder argument)
35 | {
36 | arguments.Add(argument);
37 | return this;
38 | }
39 |
40 | ///
41 | /// 添加方法的参数。
42 | ///
43 | /// 方法的参数。
44 | /// 参数的名称。
45 | /// 当前方法调用表达式构造器。
46 | public InvocationExpressionBuilder Argument(ExpressionBuilder argument, string name)
47 | {
48 | arguments.Add(argument, name);
49 | return this;
50 | }
51 |
52 | ///
53 | /// 构造方法调用表达式。
54 | ///
55 | /// 语法的格式信息。
56 | /// 方法调用表达式。
57 | public override InvocationExpressionSyntax GetSyntax(SyntaxFormat format)
58 | {
59 | if (arguments.Count == 0)
60 | {
61 | return SyntaxFactory.InvocationExpression(expression.GetSyntax(format));
62 | }
63 | else
64 | {
65 | return SyntaxFactory.InvocationExpression(expression.GetSyntax(format), arguments.GetSyntax(format));
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Expressions/MemberAccessExpressionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 成员访问表达式的构造器。
8 | ///
9 | internal sealed class MemberAccessExpressionBuilder : ExpressionBuilder
10 | {
11 | ///
12 | /// 对象表达式。
13 | ///
14 | private readonly ExpressionBuilder expression;
15 | ///
16 | /// 成员名称。
17 | ///
18 | private readonly string name;
19 |
20 | ///
21 | /// 使用指定的对象表达式和成员名称初始化 类的新实例。
22 | ///
23 | /// 对象表达式。
24 | /// 成员名称。
25 | public MemberAccessExpressionBuilder(ExpressionBuilder expression, string name)
26 | {
27 | this.expression = expression;
28 | this.name = name;
29 | }
30 |
31 | ///
32 | /// 构造成员访问表达式。
33 | ///
34 | /// 语法格式。
35 | /// 成员访问表达式。
36 | public override MemberAccessExpressionSyntax GetSyntax(SyntaxFormat format)
37 | {
38 | return SyntaxFactory.MemberAccessExpression(
39 | SyntaxKind.SimpleMemberAccessExpression,
40 | expression.GetSyntax(format),
41 | (SimpleNameSyntax)SyntaxFactory.ParseTypeName(name));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Expressions/ParenthesizedExpressionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 括号表达式的构造器。
8 | ///
9 | internal class ParenthesizedExpressionBuilder : ExpressionBuilder
10 | {
11 | ///
12 | /// 括号内的表达式。
13 | ///
14 | private readonly ExpressionBuilder expression;
15 |
16 | ///
17 | /// 使用括号内的表达式初始化 类的新实例。
18 | ///
19 | /// 括号内的表达式。
20 | public ParenthesizedExpressionBuilder(ExpressionBuilder expression)
21 | {
22 | this.expression = expression;
23 | }
24 |
25 | ///
26 | /// 构造括号表达式。
27 | ///
28 | /// 语法的格式信息。
29 | /// 括号表达式。
30 | public override ParenthesizedExpressionSyntax GetSyntax(SyntaxFormat format)
31 | {
32 | return SyntaxFactory.ParenthesizedExpression(expression.GetSyntax(format));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Expressions/PrefixUnaryExpressionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 | using Microsoft.CodeAnalysis.CSharp;
4 |
5 | namespace Cyjb.Compilers.CodeAnalysis;
6 |
7 | ///
8 | /// 前缀一元表达式的构造器。
9 | ///
10 | internal class PrefixUnaryExpressionBuilder : ExpressionBuilder
11 | {
12 | ///
13 | /// 前缀一元表达式的类型。
14 | ///
15 | private readonly SyntaxKind kind;
16 | ///
17 | /// 前缀一元表达式的操作数表达式。
18 | ///
19 | private readonly ExpressionBuilder operand;
20 |
21 | ///
22 | /// 使用指定的表达式初始化 类的新实例。
23 | ///
24 | /// 表达式的类型。
25 | /// 操作数表达式。
26 | public PrefixUnaryExpressionBuilder(SyntaxKind kind, ExpressionBuilder operand)
27 | {
28 | this.kind = kind;
29 | this.operand = operand;
30 | }
31 |
32 | ///
33 | /// 构造前缀一元表达式。
34 | ///
35 | /// 语法的格式信息。
36 | /// 前缀一元表达式。
37 | public override PrefixUnaryExpressionSyntax GetSyntax(SyntaxFormat format)
38 | {
39 | return SyntaxFactory.PrefixUnaryExpression(kind, operand.GetSyntax(format));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Expressions/TypeOfExpressionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// typeof 表达式构造器。
8 | ///
9 | internal class TypeOfExpressionBuilder : ExpressionBuilder
10 | {
11 | ///
12 | /// 类型。
13 | ///
14 | private readonly TypeBuilder type;
15 |
16 | ///
17 | /// 使用指定的类型初始化 类的新实例。
18 | ///
19 | /// 类型。
20 | public TypeOfExpressionBuilder(TypeBuilder type)
21 | {
22 | this.type = type;
23 | }
24 |
25 | ///
26 | /// 构造 typeof 表达式。
27 | ///
28 | /// 语法的格式信息。
29 | /// typeof 表达式。
30 | public override TypeOfExpressionSyntax GetSyntax(SyntaxFormat format)
31 | {
32 | return SyntaxFactory.TypeOfExpression(type.GetSyntax(format));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/ModifierBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 修饰符的构造器。
8 | ///
9 | internal sealed class ModifierBuilder
10 | {
11 | ///
12 | /// 修饰符列表。
13 | ///
14 | private readonly List modifiers = new();
15 |
16 | ///
17 | /// 获取修饰符的个数。
18 | ///
19 | public int Count => modifiers.Count;
20 |
21 | ///
22 | /// 添加修饰符。
23 | ///
24 | /// 要添加的修饰符。
25 | /// 当前修饰符构造器。
26 | public ModifierBuilder Add(params SyntaxKind[] modifiers)
27 | {
28 | this.modifiers.AddRange(modifiers);
29 | return this;
30 | }
31 |
32 | ///
33 | /// 构造修饰符的节点列表。
34 | ///
35 | /// 语法格式。
36 | /// 修饰符的节点列表。
37 | public SyntaxTokenList GetSyntax(SyntaxFormat format)
38 | {
39 | if (modifiers.Count == 0)
40 | {
41 | return SyntaxFactory.TokenList();
42 | }
43 | List tokens = new();
44 | bool isFirst = true;
45 | foreach (SyntaxKind modifier in modifiers)
46 | {
47 | SyntaxToken token = SyntaxFactory.Token(modifier);
48 | if (isFirst)
49 | {
50 | token = token.WithLeadingTrivia(format.Indentation);
51 | isFirst = false;
52 | }
53 | else
54 | {
55 | token = token.WithLeadingTrivia(SyntaxFactory.Space);
56 | }
57 | tokens.Add(token);
58 | }
59 | return SyntaxFactory.TokenList(tokens);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/ParameterBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.CodeAnalysis.CSharp;
6 |
7 | ///
8 | /// 形参的构造器。
9 | ///
10 | internal sealed class ParameterBuilder
11 | {
12 | ///
13 | /// 参数的名称。
14 | ///
15 | private readonly string name;
16 | ///
17 | /// 参数类型。
18 | ///
19 | private TypeBuilder? type;
20 |
21 | ///
22 | /// 使用指定的参数名称初始化 类的新实例。
23 | ///
24 | /// 参数的名称。
25 | public ParameterBuilder(string name)
26 | {
27 | this.name = name;
28 | }
29 |
30 | ///
31 | /// 是否是简单参数(只包含参数名称)。
32 | ///
33 | public bool IsSimple => type == null;
34 |
35 | ///
36 | /// 设置参数的类型。
37 | ///
38 | /// 参数的类型。
39 | /// 当前方法形参的构造器。
40 | public ParameterBuilder Type(TypeBuilder type)
41 | {
42 | this.type = type;
43 | return this;
44 | }
45 |
46 | ///
47 | /// 构造形参语法节点。
48 | ///
49 | /// 语法的格式信息。
50 | /// 形参语法节点。
51 | public ParameterSyntax GetSyntax(SyntaxFormat format)
52 | {
53 | ParameterSyntax syntax = SyntaxFactory.Parameter(SyntaxFactory.Identifier(name));
54 | if (type != null)
55 | {
56 | syntax = syntax.WithType(type.GetSyntax(format).WithTrailingTrivia(SyntaxFactory.Space));
57 | }
58 | return syntax;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/ParameterListBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 形参列表的构造器。
8 | ///
9 | internal sealed class ParameterListBuilder
10 | {
11 | ///
12 | /// 形参列表。
13 | ///
14 | private readonly List parameters = new();
15 |
16 | ///
17 | /// 参数的个数。
18 | ///
19 | public int Count => parameters.Count;
20 | ///
21 | /// 是否是简单参数列表(只包含单个参数)。
22 | ///
23 | public bool IsSimple => parameters.Count == 1 && parameters[0].IsSimple;
24 |
25 | ///
26 | /// 添加指定的形参。
27 | ///
28 | /// 参数的名称。
29 | /// 当前形参列表构造器。
30 | public ParameterListBuilder Add(string name)
31 | {
32 | parameters.Add(new ParameterBuilder(name));
33 | return this;
34 | }
35 |
36 | ///
37 | /// 添加指定的形参。
38 | ///
39 | /// 参数的名称。
40 | /// 参数的类型。
41 | /// 当前形参列表构造器。
42 | public ParameterListBuilder Add(string name, TypeBuilder type)
43 | {
44 | parameters.Add(new ParameterBuilder(name).Type(type));
45 | return this;
46 | }
47 |
48 | ///
49 | /// 构造简单形参。
50 | ///
51 | /// 语法的格式信息。
52 | /// 简单形参。
53 | public ParameterSyntax GetSimpleSyntax(SyntaxFormat format)
54 | {
55 | return parameters[0].GetSyntax(format);
56 | }
57 |
58 | ///
59 | /// 构造形参的列表。
60 | ///
61 | /// 语法的格式信息。
62 | /// 形参列表。
63 | public ParameterListSyntax GetSyntax(SyntaxFormat format)
64 | {
65 | if (parameters.Count == 0)
66 | {
67 | return SyntaxFactory.ParameterList();
68 | }
69 | return SyntaxFactory.ParameterList(SyntaxBuilder.SeparatedList(
70 | parameters.Select(arg => arg.GetSyntax(format)), format));
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Pattern/BinaryPatternBuilder.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.CSharp;
4 | using Microsoft.CodeAnalysis.CSharp.Syntax;
5 |
6 | namespace Cyjb.Compilers.CodeAnalysis;
7 |
8 | ///
9 | /// 二元模式的构造器。
10 | ///
11 | internal class BinaryPatternBuilder : PatternBuilder
12 | {
13 | ///
14 | /// 二元模式的类型。
15 | ///
16 | private readonly SyntaxKind kind;
17 | ///
18 | /// 二元模式左侧的模式。
19 | ///
20 | private readonly PatternBuilder left;
21 | ///
22 | /// 二元模式右侧的模式。
23 | ///
24 | private readonly PatternBuilder right;
25 |
26 | ///
27 | /// 使用指定的模式初始化 类的新实例。
28 | ///
29 | /// 模式的类型。
30 | /// 左侧的模式。
31 | /// 右侧的模式。
32 | public BinaryPatternBuilder(SyntaxKind kind, PatternBuilder left, PatternBuilder right)
33 | {
34 | this.kind = kind;
35 | this.left = left;
36 | this.right = right;
37 | }
38 |
39 | ///
40 | /// 构造二元模式。
41 | ///
42 | /// 语法的格式信息。
43 | /// 二元模式。
44 | public override BinaryPatternSyntax GetSyntax(SyntaxFormat format)
45 | {
46 | return SyntaxFactory.BinaryPattern(kind,
47 | left.GetSyntax(format).WithTrailingTrivia(SyntaxFactory.Space),
48 | right.GetSyntax(format).WithLeadingTrivia(SyntaxFactory.Space));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Pattern/PatternBuilder.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.Compilers.CodeAnalysis;
6 |
7 | ///
8 | /// 模式的构造器。
9 | ///
10 | internal abstract class PatternBuilder
11 | {
12 | ///
13 | /// 返回小于等于模式。
14 | ///
15 | /// 小于等于模式。
16 | public static RelationalPatternBuilder LessThanEquals(ExpressionBuilder expression) =>
17 | new(SyntaxKind.LessThanEqualsToken, expression);
18 |
19 | ///
20 | /// 返回大于等于模式。
21 | ///
22 | /// 大于等于模式。
23 | public static RelationalPatternBuilder GreaterThanEquals(ExpressionBuilder expression) =>
24 | new(SyntaxKind.GreaterThanEqualsToken, expression);
25 |
26 | ///
27 | /// 构造模式语法节点。
28 | ///
29 | /// 语法的格式信息。
30 | /// 表达式语法节点。
31 | public abstract PatternSyntax GetSyntax(SyntaxFormat format);
32 |
33 | ///
34 | /// 返回当前模式与指定模式的构造器。
35 | ///
36 | /// 二元模式构造器。
37 | public BinaryPatternBuilder And(PatternBuilder pattern)
38 | {
39 | return new BinaryPatternBuilder(SyntaxKind.AndPattern, this, pattern);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Pattern/RelationalPatternBuilder.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.Compilers.CodeAnalysis;
6 |
7 | ///
8 | /// 关系模式的构造器。
9 | ///
10 | internal class RelationalPatternBuilder : PatternBuilder
11 | {
12 | ///
13 | /// 关系模式的类型。
14 | ///
15 | private readonly SyntaxKind kind;
16 | ///
17 | /// 关系模式的表达式。
18 | ///
19 | private readonly ExpressionBuilder expression;
20 |
21 | ///
22 | /// 使用指定的表达式初始化 类的新实例。
23 | ///
24 | /// 表达式的类型。
25 | /// 关系模式的表达式。
26 | public RelationalPatternBuilder(SyntaxKind kind, ExpressionBuilder expression)
27 | {
28 | this.kind = kind;
29 | this.expression = expression;
30 | }
31 |
32 | ///
33 | /// 构造关系模式。
34 | ///
35 | /// 语法的格式信息。
36 | /// 关系模式。
37 | public override RelationalPatternSyntax GetSyntax(SyntaxFormat format)
38 | {
39 | return SyntaxFactory.RelationalPattern(
40 | SyntaxFactory.Token(kind).WithTrailingTrivia(SyntaxFactory.Space),
41 | expression.GetSyntax(format));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/SeparatedListUtils.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 相关的工具方法。
8 | ///
9 | internal static class SeparatedListUtils
10 | {
11 | ///
12 | /// 逗号单元。
13 | ///
14 | private static readonly SyntaxToken CommaToken = SyntaxFactory.Token(SyntaxKind.CommaToken)
15 | .WithTrailingTrivia(SyntaxFactory.Space);
16 |
17 | ///
18 | /// 返回指定项个数的分隔符列表。
19 | ///
20 | /// 项的个数。
21 | /// 分隔符列表。
22 | public static IEnumerable GetSeparators(int itemCount)
23 | {
24 | if (itemCount <= 1)
25 | {
26 | return Array.Empty();
27 | }
28 | return Enumerable.Repeat(CommaToken, itemCount - 1);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Statements/BlockBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.CodeAnalysis.CSharp;
6 |
7 | ///
8 | /// 语句块的构造器。
9 | ///
10 | internal sealed class BlockBuilder : StatementBuilder
11 | {
12 | ///
13 | /// 包含的语句列表。
14 | ///
15 | private readonly List statements = new();
16 |
17 | ///
18 | /// 添加指定的语句。
19 | ///
20 | /// 语句。
21 | /// 当前语句块构造器。
22 | public BlockBuilder Add(StatementBuilder statement)
23 | {
24 | statements.Add(statement);
25 | return this;
26 | }
27 |
28 | ///
29 | /// 构造语句块语法节点。
30 | ///
31 | /// 语法的格式信息。
32 | /// 语句块语法节点。
33 | public override BlockSyntax GetSyntax(SyntaxFormat format)
34 | {
35 | SyntaxFormat stmFormat = format.IncDepth();
36 | return SyntaxFactory.Block(
37 | SyntaxFactory.Token(SyntaxKind.OpenBraceToken)
38 | .WithLeadingTrivia(GetLeadingTrivia(format))
39 | .WithTrailingTrivia(format.EndOfLine),
40 | SyntaxFactory.List(statements.Select(stm => stm.GetSyntax(stmFormat))),
41 | SyntaxFactory.Token(SyntaxKind.CloseBraceToken)
42 | .WithLeadingTrivia(format.Indentation)
43 | .WithTrailingTrivia(format.EndOfLine)
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Statements/BreakStatementBuilder.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 | using Microsoft.CodeAnalysis.CSharp;
4 | using Microsoft.CodeAnalysis;
5 |
6 | namespace Cyjb.Compilers.CodeAnalysis;
7 |
8 | ///
9 | /// break 语句的构造器。
10 | ///
11 | internal class BreakStatementBuilder : StatementBuilder
12 | {
13 | ///
14 | /// 构造 break 语句。
15 | ///
16 | /// 语法的格式信息。
17 | /// break 语句。
18 | public override BreakStatementSyntax GetSyntax(SyntaxFormat format)
19 | {
20 | return SyntaxFactory.BreakStatement()
21 | .WithLeadingTrivia(format.Indentation)
22 | .WithTrailingTrivia(format.EndOfLine);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Statements/ExpressionStatementBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.CodeAnalysis.CSharp;
6 |
7 | ///
8 | /// 表达式语句的构造器。
9 | ///
10 | internal sealed class ExpressionStatementBuilder : StatementBuilder
11 | {
12 | ///
13 | /// 语句包含的表达式。
14 | ///
15 | private readonly ExpressionBuilder expression;
16 |
17 | ///
18 | /// 使用指定的表达式初始化 类的新实例。
19 | ///
20 | /// 语句包含的表达式。
21 | public ExpressionStatementBuilder(ExpressionBuilder expression)
22 | {
23 | this.expression = expression;
24 | }
25 |
26 | ///
27 | /// 构造返回语句。
28 | ///
29 | /// 语法的格式信息。
30 | /// 返回语句。
31 | public override ExpressionStatementSyntax GetSyntax(SyntaxFormat format)
32 | {
33 | return SyntaxFactory.ExpressionStatement(expression.GetSyntax(format))
34 | .WithLeadingTrivia(GetLeadingTrivia(format)).WithTrailingTrivia(format.EndOfLine);
35 | }
36 |
37 | ///
38 | /// 允许从表达式构造器隐式转换为 对象。
39 | ///
40 | /// 要转换的表达式构造器。
41 | /// 转换到的 对象。
42 | public static implicit operator ExpressionStatementBuilder(ExpressionBuilder expression)
43 | {
44 | return new ExpressionStatementBuilder(expression);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Statements/GotoStatementBuilder.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.Compilers.CodeAnalysis;
6 |
7 | ///
8 | /// 表示 goto 语句的构造器。
9 | ///
10 | internal class GotoStatementBuilder : StatementBuilder
11 | {
12 | ///
13 | /// goto 语句的类型。
14 | ///
15 | private readonly SyntaxKind kind;
16 | ///
17 | /// goto 语句的表达式。
18 | ///
19 | private readonly ExpressionBuilder expression;
20 |
21 | ///
22 | /// 使用指定的标签名初始化 类的新实例。
23 | ///
24 | /// 要跳转的标签名。
25 | public GotoStatementBuilder(string identifier)
26 | {
27 | kind = SyntaxKind.GotoStatement;
28 | expression = SyntaxFactory.IdentifierName(identifier);
29 | }
30 |
31 | ///
32 | /// 构造 goto 语句。
33 | ///
34 | /// 语法的格式信息。
35 | /// goto 语句。
36 | public override GotoStatementSyntax GetSyntax(SyntaxFormat format)
37 | {
38 | return SyntaxFactory.GotoStatement(kind,
39 | SyntaxFactory.Token(SyntaxKind.GotoKeyword)
40 | .WithLeadingTrivia(format.Indentation)
41 | .WithTrailingTrivia(SyntaxFactory.Space),
42 | SyntaxFactory.Token(SyntaxKind.None),
43 | expression.GetSyntax(format),
44 | SyntaxFactory.Token(SyntaxKind.SemicolonToken).WithTrailingTrivia(format.EndOfLine)
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Statements/LabeledStatementBuilder.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 | using Microsoft.CodeAnalysis.CSharp;
4 |
5 | namespace Cyjb.Compilers.CodeAnalysis;
6 |
7 | ///
8 | /// 标签语句的构造器。
9 | ///
10 | internal class LabeledStatementBuilder : StatementBuilder
11 | {
12 | ///
13 | /// 标签的标识符。
14 | ///
15 | private readonly string identifier;
16 | ///
17 | /// 标签的语句。
18 | ///
19 | private readonly StatementBuilder statement;
20 |
21 | ///
22 | /// 使用标签标识符和语句初始化 类的新实例。
23 | ///
24 | /// 标签的标识符。
25 | /// 标签的语句。
26 | public LabeledStatementBuilder(string identifier, StatementBuilder statement)
27 | {
28 | this.identifier = identifier;
29 | this.statement = statement;
30 | }
31 |
32 | ///
33 | /// 构造标签语句。
34 | ///
35 | /// 语法的格式信息。
36 | /// 标签语句。
37 | public override LabeledStatementSyntax GetSyntax(SyntaxFormat format)
38 | {
39 | return SyntaxFactory.LabeledStatement(
40 | SyntaxFactory.Identifier(identifier).WithLeadingTrivia(format.DecDepth().Indentation),
41 | SyntaxFactory.Token(SyntaxKind.ColonToken).WithTrailingTrivia(format.EndOfLine),
42 | statement.GetSyntax(format)
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Statements/ReturnStatementBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 返回语句的构造器。
8 | ///
9 | internal sealed class ReturnStatementBuilder : StatementBuilder
10 | {
11 | ///
12 | /// 要返回的表达式。
13 | ///
14 | private readonly ExpressionBuilder expression;
15 |
16 | ///
17 | /// 使用指定的表达式初始化 类的新实例。
18 | ///
19 | /// 要返回的表达式。
20 | public ReturnStatementBuilder(ExpressionBuilder expression)
21 | {
22 | this.expression = expression;
23 | }
24 |
25 | ///
26 | /// 构造返回语句。
27 | ///
28 | /// 语法的格式信息。
29 | /// 返回语句。
30 | public override ReturnStatementSyntax GetSyntax(SyntaxFormat format)
31 | {
32 | return SyntaxFactory.ReturnStatement(
33 | SyntaxFactory.Token(SyntaxKind.ReturnKeyword)
34 | .WithLeadingTrivia(GetLeadingTrivia(format))
35 | .WithTrailingTrivia(SyntaxFactory.Space),
36 | expression.GetSyntax(format),
37 | SyntaxFactory.Token(SyntaxKind.SemicolonToken)
38 | .WithTrailingTrivia(format.EndOfLine)
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/Builders/Statements/WhileStatementBuilder.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 | using Microsoft.CodeAnalysis.CSharp;
4 |
5 | namespace Cyjb.Compilers.CodeAnalysis;
6 |
7 | ///
8 | /// while 语句的构造器。
9 | ///
10 | internal class WhileStatementBuilder : StatementBuilder
11 | {
12 | ///
13 | /// while 语句的条件表达式。
14 | ///
15 | private readonly ExpressionBuilder condition;
16 | ///
17 | /// 包含的语句块。
18 | ///
19 | private readonly BlockBuilder block = new();
20 |
21 | ///
22 | /// 初始化 类的新实例。
23 | ///
24 | /// while 语句的条件表达式。
25 | public WhileStatementBuilder(ExpressionBuilder condition)
26 | {
27 | this.condition = condition;
28 | }
29 |
30 | ///
31 | /// 添加指定的语句。
32 | ///
33 | /// 语句。
34 | /// 当前语句块构造器。
35 | public WhileStatementBuilder Statement(StatementBuilder statement)
36 | {
37 | block.Add(statement);
38 | return this;
39 | }
40 |
41 | ///
42 | /// 构造 while 语句。
43 | ///
44 | /// 语法的格式信息。
45 | /// while 语句。
46 | public override WhileStatementSyntax GetSyntax(SyntaxFormat format)
47 | {
48 | return SyntaxFactory.WhileStatement(
49 | SyntaxFactory.Token(SyntaxKind.WhileKeyword)
50 | .WithLeadingTrivia(GetLeadingTrivia(format))
51 | .WithTrailingTrivia(SyntaxFactory.Space),
52 | SyntaxFactory.Token(SyntaxKind.OpenParenToken),
53 | condition.GetSyntax(format),
54 | SyntaxFactory.Token(SyntaxKind.CloseParenToken)
55 | .WithTrailingTrivia(format.EndOfLine),
56 | block.GetSyntax(format)
57 | );
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/IndentDetector.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.CodeAnalysis.CSharp;
6 |
7 | ///
8 | /// 语法节点的缩进检测器。
9 | ///
10 | internal class IndentDetector : CSharpSyntaxWalker
11 | {
12 | ///
13 | /// 检测到的缩进。
14 | ///
15 | private string indent = string.Empty;
16 |
17 | ///
18 | /// 获取当前缩进。
19 | ///
20 | public string Indent => indent;
21 |
22 | ///
23 | /// 访问指定的语法节点。
24 | ///
25 | /// 要访问的语法节点。
26 | public override void Visit(SyntaxNode? node)
27 | {
28 | if (node == null)
29 | {
30 | return;
31 | }
32 | if (indent.Length > 0)
33 | {
34 | // 已经检测到缩进,返回。
35 | return;
36 | }
37 | // 找到成员声明或语句的首个空白琐事作为缩进。
38 | if (node is MemberDeclarationSyntax || node is StatementSyntax)
39 | {
40 | indent = GetIndent(node);
41 | }
42 | base.Visit(node);
43 | }
44 |
45 | ///
46 | /// 返回指定语法节点的缩进。
47 | ///
48 | /// 要检查的语法节点。
49 | /// 语法节点的缩进。
50 | public static string GetIndent(SyntaxNode? node)
51 | {
52 | if (node == null)
53 | {
54 | return string.Empty;
55 | }
56 | foreach (SyntaxTrivia trivia in node.GetLeadingTrivia())
57 | {
58 | if (trivia.IsKind(SyntaxKind.EndOfLineTrivia))
59 | {
60 | continue;
61 | }
62 | else if (trivia.IsKind(SyntaxKind.WhitespaceTrivia))
63 | {
64 | return trivia.ToString();
65 | }
66 | break;
67 | }
68 | return string.Empty;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/NameSyntaxUtil.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp.Syntax;
2 |
3 | namespace Cyjb.CodeAnalysis.CSharp;
4 |
5 | ///
6 | /// 提供对 的扩展方法。
7 | ///
8 | internal static class NameSyntaxUtil
9 | {
10 | ///
11 | /// 返回当前 的 。
12 | ///
13 | /// 要检查的 对象。
14 | /// 本身,或者限定符最右侧的 。
15 | public static SimpleNameSyntax GetSimpleName(this NameSyntax name)
16 | {
17 | if (name is SimpleNameSyntax simpleName)
18 | {
19 | return simpleName;
20 | }
21 | else if (name is AliasQualifiedNameSyntax aliasQualifiedName)
22 | {
23 | return aliasQualifiedName.Name;
24 | }
25 | else if (name is QualifiedNameSyntax qualifiedName)
26 | {
27 | return qualifiedName.Right;
28 | }
29 | else
30 | {
31 | throw CommonExceptions.Unreachable();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/ParameterSyntaxUtil.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace Cyjb.CodeAnalysis.CSharp;
6 |
7 | ///
8 | /// 提供对 的扩展方法。
9 | ///
10 | internal static class ParameterSyntaxUtil
11 | {
12 | ///
13 | /// 返回当前 是否是 params 参数。
14 | ///
15 | /// 要检查的 对象。
16 | /// 如果 是 params 参数,则为 true;否则为 false。
17 | public static bool IsParamsArray(this ParameterSyntax param)
18 | {
19 | foreach (var modifier in param.Modifiers)
20 | {
21 | if (modifier.IsKind(SyntaxKind.ParamsKeyword))
22 | {
23 | return true;
24 | }
25 | }
26 | return false;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/SyntaxTokenUtils.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 |
3 | namespace Cyjb.CodeAnalysis.CSharp;
4 |
5 | ///
6 | /// 提供 的扩展方法。
7 | ///
8 | internal static class SyntaxTokenUtils
9 | {
10 | ///
11 | /// 插入指定的前置琐事。
12 | ///
13 | /// 语法单元。
14 | /// 要插入的索引。
15 | /// 要插入的琐事。
16 | /// 更新后的语法单元。
17 | public static SyntaxToken InsertLeadingTrivia(this SyntaxToken token, int index, IEnumerable? trivia)
18 | {
19 | if (trivia == null)
20 | {
21 | return token;
22 | }
23 | return token.WithLeadingTrivia(token.LeadingTrivia.InsertRange(index, trivia));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Generator/CodeAnalysis.CSharp/XmlNodeSyntaxOrString.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.CodeAnalysis.CSharp;
5 |
6 | ///
7 | /// 表示 或者字符串。
8 | ///
9 | internal sealed class XmlNodeSyntaxOrString
10 | {
11 | ///
12 | /// 使用指定的 初始化 类的新实例。
13 | ///
14 | /// 要封装的 。
15 | public XmlNodeSyntaxOrString(XmlNodeSyntax node)
16 | {
17 | Node = node;
18 | }
19 |
20 | ///
21 | /// 使用指定的字符串初始化 类的新实例。
22 | ///
23 | /// 要封装的字符串。
24 | public XmlNodeSyntaxOrString(string text)
25 | {
26 | Node = SyntaxFactory.XmlText(text);
27 | }
28 |
29 | ///
30 | /// 包含的 。
31 | ///
32 | public XmlNodeSyntax Node { get; }
33 |
34 | ///
35 | /// 允许从 实例隐式转换为 实例。
36 | ///
37 | /// 要封装的 。
38 | public static implicit operator XmlNodeSyntaxOrString(XmlNodeSyntax node)
39 | {
40 | return new XmlNodeSyntaxOrString(node);
41 | }
42 |
43 | ///
44 | /// 允许从字符串实例隐式转换为 实例。
45 | ///
46 | /// 要封装的字符串。
47 | public static implicit operator XmlNodeSyntaxOrString(string text)
48 | {
49 | return new XmlNodeSyntaxOrString(text);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Generator/Controller.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace Cyjb.Compilers;
5 |
6 | ///
7 | /// 词法/语法分析控制器。
8 | ///
9 | internal abstract class Controller
10 | {
11 | ///
12 | /// 使用指定的控制器名称和标识符类型初始化 类的新实例。
13 | ///
14 | /// 模板上下文。
15 | /// 控制器语法节点。
16 | /// 标识符类型。
17 | protected Controller(TransformationContext context, ClassDeclarationSyntax syntax, string kindType)
18 | {
19 | Context = context;
20 | Name = syntax.Identifier.ToString();
21 | ControllerType = Name.AsName();
22 | if (syntax.TypeParameterList != null)
23 | {
24 | foreach (TypeParameterSyntax typeParam in syntax.TypeParameterList.Parameters)
25 | {
26 | ControllerType.TypeArgument(typeParam.ToString());
27 | }
28 | }
29 | KindType = kindType;
30 | Format = new SyntaxFormat(syntax).IncDepth();
31 | }
32 |
33 | ///
34 | /// 获取控制器的名称。
35 | ///
36 | public string Name { get; }
37 | ///
38 | /// 获取控制器的类型。
39 | ///
40 | public NameBuilder ControllerType { get; }
41 |
42 | ///
43 | /// 获取模板上下文。
44 | ///
45 | protected TransformationContext Context { get; }
46 | ///
47 | /// 获取标识符的类型。
48 | ///
49 | protected string KindType { get; }
50 | ///
51 | /// 获取语法的格式化信息。
52 | ///
53 | protected SyntaxFormat Format { get; }
54 |
55 | ///
56 | /// 解析控制器语法节点。
57 | ///
58 | /// 控制器语法节点。
59 | public abstract void Parse(ClassDeclarationSyntax controllerSyntax);
60 |
61 | ///
62 | /// 生成控制器的成员。
63 | ///
64 | /// 控制器的成员。
65 | public abstract IEnumerable Generate();
66 | }
67 |
--------------------------------------------------------------------------------
/Generator/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013, CYJB
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice, this
11 | list of conditions and the following disclaimer in the documentation and/or
12 | other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/Generator/Lexers/LexerController.CharClass.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using Cyjb.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp;
4 |
5 | namespace Cyjb.Compilers.Lexers;
6 |
7 | internal sealed partial class LexerController
8 | {
9 | ///
10 | /// 声明词法分析器数据的字符类 Unicode 类别。
11 | ///
12 | /// 词法分析器数据
13 | /// 字符类 Unicode 类别声明与。
14 | public static LocalDeclarationStatementBuilder? DeclareCharClassCategories(LexerData data)
15 | {
16 | if (data.CharClasses.Categories == null)
17 | {
18 | return null;
19 | }
20 | var categories = ExpressionBuilder.CreateObject().InitializerWrap(1);
21 | foreach (var pair in data.CharClasses.Categories!)
22 | {
23 | categories.Initializer(ExpressionBuilder.InitializerExpression(SyntaxKind.ComplexElementInitializerExpression)
24 | .Add(SyntaxBuilder.Type().AccessMember(pair.Key.ToString()))
25 | .Add(pair.Value));
26 | }
27 | return SyntaxBuilder.DeclareLocal>("categories")
28 | .Comment("字符类 Unicode 类别")
29 | .Value(categories);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Generator/Lexers/LexerController.Contexts.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 |
3 | namespace Cyjb.Compilers.Lexers;
4 |
5 | internal sealed partial class LexerController
6 | {
7 | ///
8 | /// 返回表示上下文的键的表达式。
9 | ///
10 | /// 上下文的键。
11 | /// 表示上下文的键的表达式。
12 | private static ExpressionBuilder GetContextKey(string key)
13 | {
14 | if (key == ContextData.Initial)
15 | {
16 | return SyntaxBuilder.Type().AccessMember("Initial");
17 | }
18 | else
19 | {
20 | return key;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Generator/Parsers/ParserController.Goto.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 |
3 | namespace Cyjb.Compilers.Parsers;
4 |
5 | internal sealed partial class ParserController
6 | {
7 | ///
8 | /// 返回指定语法分析器数据的转移检查。
9 | ///
10 | /// 转移的检查数据
11 | /// 转移检查数据。
12 | private static ExpressionBuilder GotoCheck(SymbolKind[] gotoCheck)
13 | {
14 | var builder = ExpressionBuilder.CreateArray().InitializerWrap(1);
15 | foreach (SymbolKind value in gotoCheck)
16 | {
17 | builder.Initializer(value.Syntax);
18 | }
19 | return builder;
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/Generator/Parsers/ParserController.KindMap.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 | using Microsoft.CodeAnalysis.CSharp;
3 |
4 | namespace Cyjb.Compilers.Parsers;
5 |
6 | internal sealed partial class ParserController
7 | {
8 | ///
9 | /// 返回指定符号类别字典的数据。
10 | ///
11 | /// 符号类别字典。
12 | /// 符号类别字典的数据。
13 | private static ExpressionBuilder KindMap(Dictionary map)
14 | {
15 | var builder = ExpressionBuilder.CreateObject().InitializerWrap(1);
16 | // 按照索引顺序生成起始状态
17 | foreach (var (key, value) in map.OrderBy(pair => pair.Key.Index))
18 | {
19 | builder.Initializer(ExpressionBuilder.InitializerExpression(SyntaxKind.ComplexElementInitializerExpression)
20 | .Add(key.Syntax)
21 | .Add(value));
22 | }
23 | return builder;
24 | }
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/Generator/Parsers/ParserController.Productions.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.CodeAnalysis.CSharp;
2 |
3 | namespace Cyjb.Compilers.Parsers;
4 |
5 | internal sealed partial class ParserController
6 | {
7 | ///
8 | /// 声明指定语法分析器数据的产生式数据。
9 | ///
10 | /// 语法分析器数据
11 | /// 产生式数据声明语句。
12 | private LocalDeclarationStatementBuilder DeclareProductions(ParserData data)
13 | {
14 | TypeBuilder productionType = typeof(ProductionData<>).AsName().TypeArgument(KindType);
15 | var builder = ExpressionBuilder.CreateArray().InitializerWrap(1);
16 | foreach (ProductionData production in data.Productions)
17 | {
18 | var productionBuilder = ExpressionBuilder.CreateObject(productionType).ArgumentWrap(1);
19 | builder.Initializer(productionBuilder);
20 | productionBuilder.Argument(production.HeadIndex);
21 | productionBuilder.Argument(production.Head.Syntax);
22 | if (production.Action == null)
23 | {
24 | productionBuilder.Argument(ExpressionBuilder.Null());
25 | }
26 | else if (production.Action == ProductionAction.Optional)
27 | {
28 | productionBuilder.Argument(SyntaxBuilder.Type().AccessMember("Optional"));
29 | }
30 | else if (production.Action == ProductionAction.More)
31 | {
32 | productionBuilder.Argument(SyntaxBuilder.Type().AccessMember("More"));
33 | }
34 | else
35 | {
36 | var action = ExpressionBuilder.Lambda()
37 | .Parameter("c", Name)
38 | .Body("c".AsName().AccessMember(actionMap[production.Action]).Invoke());
39 | productionBuilder.Argument(action);
40 | }
41 | foreach (SymbolKind kind in production.Body)
42 | {
43 | productionBuilder.Argument(kind.Syntax);
44 | }
45 | }
46 | return SyntaxBuilder.DeclareLocal(productionType.Clone().Array(), "productions")
47 | .Comment("产生式数据").Value(builder);
48 | }
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/Generator/Properties/PublishProfiles/Publish.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Release
8 | Any CPU
9 | bin\publish\
10 | FileSystem
11 | net6.0
12 | false
13 |
14 |
--------------------------------------------------------------------------------
/Generator/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "CompilerGenerator": {
4 | "commandName": "Project",
5 | "commandLineArgs": "D:\\Workspace_DotNet\\Cyjb.Compilers\\TestCompilers\\Lexers\\TestCalcLexer.cs"
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/Generator/README.md:
--------------------------------------------------------------------------------
1 | Cyjb.Compilers.Generator
2 | ====
3 |
4 | 允许根据设计时词法分析和语法分析定义,生成相应的实现,基于 .NET 6。
5 |
6 | 使用方式:
7 |
8 | ```bash
9 | Generator
10 | ```
11 |
12 | 参数:
13 |
14 | - `` 已声明的词法/语法分析控制器文件。
15 |
16 | 输出:
17 |
18 | 生成的词法/语法分析器代码。
19 |
20 | 欢迎访问我的[博客](http://www.cnblogs.com/cyjb/)获取更多信息。
21 |
22 | C# 词法分析器系列博文
23 |
24 | - [C# 词法分析器(一)词法分析介绍](http://www.cnblogs.com/cyjb/archive/p/LexerIntroduce.html)
25 | - [C# 词法分析器(二)输入缓冲和代码定位](http://www.cnblogs.com/cyjb/archive/p/LexerInputBuffer.html)
26 | - [C# 词法分析器(三)正则表达式](http://www.cnblogs.com/cyjb/archive/p/LexerRegex.html)
27 | - [C# 词法分析器(四)构造 NFA](http://www.cnblogs.com/cyjb/archive/p/LexerNfa.html)
28 | - [C# 词法分析器(五)转换 DFA](http://www.cnblogs.com/cyjb/archive/p/LexerDfa.html)
29 | - [C# 词法分析器(六)构造词法分析器](http://www.cnblogs.com/cyjb/archive/p/LexerLexer.html)
30 | - [C# 词法分析器(七)总结](http://www.cnblogs.com/cyjb/p/LexerSummary.html)
31 |
--------------------------------------------------------------------------------
/Generator/Resources.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Generator/Resources.cs
--------------------------------------------------------------------------------
/Generator/Resources.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="$(PkgCyjb)\content\ResourcesTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/Generator/TransformationContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 |
3 | namespace Cyjb.Compilers;
4 |
5 | ///
6 | /// 表示转换的上下文。
7 | ///
8 | internal class TransformationContext
9 | {
10 | ///
11 | /// 获取是否包含错误。
12 | ///
13 | public bool HasError { get; private set; }
14 |
15 | ///
16 | /// 添加指定的错误信息。
17 | ///
18 | /// 错误信息。
19 | /// 语法节点。
20 | public void AddError(string message, SyntaxNode node)
21 | {
22 | AddError(message, node.GetLocation());
23 | }
24 |
25 | ///
26 | /// 添加指定的错误信息。
27 | ///
28 | /// 错误信息。
29 | /// 错误信息的位置。
30 | public void AddError(string message, Location? location)
31 | {
32 | HasError = true;
33 | string position = string.Empty;
34 | if (location != null)
35 | {
36 | FileLinePositionSpan span = location.GetLineSpan();
37 | string file = Path.GetFileName(span.Path);
38 | int line = span.StartLinePosition.Line + 1;
39 | int column = span.StartLinePosition.Character + 1;
40 | position = $"{file}({line},{column}): ";
41 | }
42 | Console.WriteLine(position + message);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Generator/tests/TestCalcLexer.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 |
3 | namespace TestCompilers.Lexers
4 | {
5 |
6 | public enum Calc { Id, Add, Sub, Mul, Div, Pow, LBrace, RBrace }
7 |
8 | ///
9 | /// 用于单元测试的计算器控制器。
10 | ///
11 | [LexerSymbol("\\+", Kind = Calc.Add)]
12 | [LexerSymbol("\\-", Kind = Calc.Sub)]
13 | [LexerSymbol("\\*", Kind = Calc.Mul)]
14 | [LexerSymbol("\\/", Kind = Calc.Div)]
15 | [LexerSymbol("\\^", Kind = Calc.Pow)]
16 | [LexerSymbol("\\(", Kind = Calc.LBrace)]
17 | [LexerSymbol("\\)", Kind = Calc.RBrace)]
18 | [LexerSymbol("\\)", Kind = Calc.RBrace)]
19 | [LexerSymbol("\\)", Kind = Calc.RBrace)]
20 | [LexerSymbol("\\s")]
21 | public partial class TestCalcLexer : LexerController
22 | where T : struct
23 | {
24 | ///
25 | /// 数字的终结符定义。
26 | ///
27 | [LexerSymbol("[0-9]+", Kind = Calc.Id)]
28 | public void DigitAction()
29 | {
30 | Value = int.Parse(Text);
31 | Accept();
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/Generator/tests/TestEscapeStrController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Text;
4 | using Cyjb.Compilers.Lexers;
5 |
6 | namespace TestCompilers.Lexers;
7 |
8 | ///
9 | /// 用于单元测试的转义字符串控制器。
10 | ///
11 | [LexerContext("str")]
12 | [LexerContext("vstr")]
13 |
14 | public partial class TestEscapeStrController : LexerController
15 | {
16 | private const string CtxStr = "str";
17 | private const string CtxVstr = "vstr";
18 |
19 | ///
20 | /// 当前起始索引。
21 | ///
22 | private int curStart;
23 | ///
24 | /// 处理后的文本。
25 | ///
26 | private readonly StringBuilder decodedText = new();
27 |
28 | [LexerSymbol(@"\""")]
29 | public void BeginStrAction()
30 | {
31 | PushContext(CtxStr);
32 | curStart = Start;
33 | decodedText.Clear();
34 | }
35 |
36 | [LexerSymbol(@"@\""")]
37 | public void BeginVstrAction()
38 | {
39 | PushContext(CtxVstr);
40 | curStart = Start;
41 | decodedText.Clear();
42 | }
43 |
44 | [LexerSymbol(@"\""", Kind = Str.Str)]
45 | public void EndAction()
46 | {
47 | PopContext();
48 | Start = curStart;
49 | Text = decodedText.ToString();
50 | }
51 |
52 | [LexerSymbol(@"\\u[0-9]{4}")]
53 | [LexerSymbol(@"\\x[0-9]{2}")]
54 | public void HexEscapeAction()
55 | {
56 | decodedText.Append((char)int.Parse(Text.AsSpan()[2..], NumberStyles.HexNumber));
57 | }
58 |
59 | [LexerSymbol(@"\\n")]
60 | public void EscapeLFAction()
61 | {
62 | decodedText.Append('\n');
63 | }
64 |
65 | [LexerSymbol(@"\\\""")]
66 | public void EscapeQuoteAction()
67 | {
68 | decodedText.Append('\"');
69 | }
70 |
71 | [LexerSymbol(@"\\r")]
72 | public void EscapeCRAction()
73 | {
74 | decodedText.Append('\r');
75 | }
76 |
77 | [LexerSymbol(@"<*>.")]
78 | public void CopyAction()
79 | {
80 | decodedText.Append(Text);
81 | }
82 |
83 | [LexerSymbol(@"\""\""")]
84 | public void VstrQuoteAction()
85 | {
86 | decodedText.Append('"');
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Generator/tests/TestEscapeStrController.second.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Text;
4 | using Cyjb.Compilers.Lexers;
5 |
6 | namespace TestCompilers.Lexers;
7 |
8 | [LexerContext("vstr2")]
9 |
10 | public partial class TestEscapeStrController
11 | {
12 | [LexerSymbol(@"\""\""")]
13 | public void VstrQuoteAction2()
14 | {
15 | decodedText.Append('"');
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/Generator/tests/TestProductionController.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 |
3 | namespace TestCompilers.Lexers;
4 |
5 | ///
6 | /// 产生式的类型。
7 | ///
8 | public enum ProductionKind
9 | {
10 | ///
11 | /// 词法单元类型。
12 | ///
13 | Id,
14 | ///
15 | /// 左小括号。
16 | ///
17 | LBrace,
18 | ///
19 | /// 右小括号。
20 | ///
21 | RBrace,
22 | ///
23 | /// 星号
24 | ///
25 | Star,
26 | ///
27 | /// 加号
28 | ///
29 | Plus,
30 | ///
31 | /// 问号
32 | ///
33 | Question,
34 | }
35 |
36 | ///
37 | /// 用于单元测试的计算器控制器。
38 | ///
39 | [LexerSymbol(@"\d+|\w[\w\d]*", Kind = ProductionKind.Id)]
40 | [LexerSymbol(@"\(", Kind = ProductionKind.LBrace)]
41 | [LexerSymbol(@"\)", Kind = ProductionKind.RBrace)]
42 | [LexerSymbol(@"\+", Kind = ProductionKind.Plus)]
43 | [LexerSymbol(@"\*", Kind = ProductionKind.Star)]
44 | [LexerSymbol(@"\?", Kind = ProductionKind.Question)]
45 | [LexerSymbol(@"\s")]
46 | public partial class TestProductionController : LexerController
47 | { }
48 |
49 |
--------------------------------------------------------------------------------
/Generator/tests/TestProductionParser.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Parsers;
2 |
3 | namespace Cyjb.Compilers.Parsers.Production;
4 |
5 | ///
6 | /// 产生式语法分析器。
7 | ///
8 | internal partial class TestProductionParser : ParserController
9 | {
10 | [ParserProduction(ProductionKind.Expression, ProductionKind.Expression, ProductionKind.Repeat)]
11 | private object? ExpressionAction()
12 | {
13 | ProductionNode node = (this[0].Value as ProductionNode)!;
14 | if (node.RepeatKind != ProductionKind.Id)
15 | {
16 | node = new ProductionNode(node);
17 | }
18 | node.Symbols.Add(this[1].Value!);
19 | return node;
20 | }
21 |
22 | [ParserProduction(ProductionKind.Expression, ProductionKind.Repeat)]
23 | [ParserProduction(ProductionKind.Repeat, ProductionKind.Item)]
24 | [ParserProduction(ProductionKind.Item, ProductionKind.Id)]
25 | private object? CopyAction()
26 | {
27 | object? value = this[0].Value;
28 | if (value is ProductionNode)
29 | {
30 | return value;
31 | }
32 | else
33 | {
34 | return new ProductionNode(value!);
35 | }
36 | }
37 |
38 | [ParserProduction(ProductionKind.Item, ProductionKind.LBrace, ProductionKind.Expression, ProductionKind.RBrace)]
39 | private object? BraceAction()
40 | {
41 | return new ProductionNode(this[1].Value!);
42 | }
43 |
44 | [ParserProduction(ProductionKind.Repeat, ProductionKind.Item, ProductionKind.Plus)]
45 | [ParserProduction(ProductionKind.Repeat, ProductionKind.Item, ProductionKind.Star)]
46 | [ParserProduction(ProductionKind.Repeat, ProductionKind.Item, ProductionKind.Question)]
47 | private object? RepeatAction()
48 | {
49 | ProductionNode node = (this[0].Value as ProductionNode)!;
50 | node.RepeatKind = this[1].Kind;
51 | return node;
52 | }
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/Generator/tests/TestSymbolValueLexer.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 |
4 | namespace TestCompilers.Lexers;
5 |
6 | ///
7 | /// 测试词法单元的值。
8 | ///
9 | public partial class TestSymbolValueLexer : LexerController
10 | {
11 | [LexerSymbol("[0-9]+", Kind = Calc.Id, Value = 101)]
12 | public void DigitAction()
13 | {
14 | Assert.AreEqual(101, Value);
15 | Accept((int)Value! + 10);
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/Generator/tests/UnitTestTemplateDiagnostics.template.cs:
--------------------------------------------------------------------------------
1 | [LexerSymbol(10, 20, 30, 40, 50)]
2 | [LexerSymbol(Regex: "f")]
3 | [LexerSymbol("F", regex : "f")]
4 | [LexerSymbol(options: RegexOptions.None, "f")]
5 | [LexerSymbol("f", Test = 10)]
6 | [LexerSymbol("F", Kind = "f", Kind = "F2")]
7 | [LexerSymbol]
8 | [LexerSymbol(10)]
9 | [LexerSymbol("T", RegexOptions.Test)]
10 | [LexerSymbol("T", 10.3)]
11 | [LexerSymbol("T", "abc")]
12 | [LexerSymbol("T", Priority = "abc")]
13 | [LexerContext("")]
14 | [LexerSymbol("
16 | {
17 | [LexerSymbol("T")]
18 | public void InvalidAction(int a) { }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Cyjb.Compilers
2 | ====
3 |
4 | [](https://www.nuget.org/packages/Cyjb.Compilers)
5 | [](https://codecov.io/gh/CYJB/Cyjb.Compilers)
6 |
7 | 提供编译相关功能,基于 .NET 6。
8 |
9 | 本项目包括一些与编译相关的功能,目前包含词法分析器和 LALR 语法分析器,以及相应的运行时。
10 |
11 | - Compilers 包含了构造词法和语法分析器的功能。
12 | - Design 提供了通过设计时 T4 模板生成词法分析器和语法分析器的能力。
13 | - Generator 是用于 T4 模板的代码生成器,其产物会由 Design 工具嵌入使用。
14 | - Runtime 提供了词法和语法分析的运行时。
15 |
16 | 详细的类库文档,请参见 [Wiki](https://github.com/CYJB/Cyjb.Compilers/wiki)。
17 |
18 | 欢迎访问我的[博客](http://www.cnblogs.com/cyjb/)获取更多信息。
19 |
20 | C# 词法分析器系列博文
21 |
22 | - [C# 词法分析器(一)词法分析介绍](http://www.cnblogs.com/cyjb/archive/p/LexerIntroduce.html)
23 | - [C# 词法分析器(二)输入缓冲和代码定位](http://www.cnblogs.com/cyjb/archive/p/LexerInputBuffer.html)
24 | - [C# 词法分析器(三)正则表达式](http://www.cnblogs.com/cyjb/archive/p/LexerRegex.html)
25 | - [C# 词法分析器(四)构造 NFA](http://www.cnblogs.com/cyjb/archive/p/LexerNfa.html)
26 | - [C# 词法分析器(五)转换 DFA](http://www.cnblogs.com/cyjb/archive/p/LexerDfa.html)
27 | - [C# 词法分析器(六)构造词法分析器](http://www.cnblogs.com/cyjb/archive/p/LexerLexer.html)
28 | - [C# 词法分析器(七)总结](http://www.cnblogs.com/cyjb/p/LexerSummary.html)
29 |
30 | C# 语法法分析器系列博文
31 |
32 | - [C# 语法分析器(一)语法分析介绍](https://www.cnblogs.com/cyjb/p/ParserIntroduce.html)
33 | - [C# 语法分析器(二)LR(0) 语法分析](https://www.cnblogs.com/cyjb/p/ParserLR_0.html)
34 | - [C# 语法分析器(三)LALR 语法分析](https://www.cnblogs.com/cyjb/p/ParserLALR.html)
35 | - [C# 语法分析器(四)二义性文法](https://www.cnblogs.com/cyjb/p/ParserAmbiguous.html)
36 | - [C# 语法分析器(五)错误恢复](https://www.cnblogs.com/cyjb/p/ParserErrorRecovery.html)
37 | - [C# 语法分析器(六)构造语法分析器](https://www.cnblogs.com/cyjb/p/ParserCreate.html)
38 |
--------------------------------------------------------------------------------
/Runtime/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // 有关程序集的常规信息通过以下
5 | // 特性集控制。更改这些特性值可修改
6 | // 与程序集关联的信息。
7 | [assembly: AssemblyTrademark("CYJB")]
8 | [assembly: AssemblyCulture("")]
9 | [assembly: CLSCompliant(true)]
10 |
11 | // 将 ComVisible 设置为 false 使此程序集中的类型
12 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
13 | // 则将该类型上的 ComVisible 特性设置为 true。
14 | [assembly: ComVisible(false)]
15 |
16 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
17 | [assembly: Guid("ca903a41-123d-48ff-a523-e6011a1859f8")]
18 |
19 |
--------------------------------------------------------------------------------
/Runtime/Cyjb.Compilers.Runtime.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | enable
5 | enable
6 | True
7 | True
8 | https://github.com/CYJB/Cyjb.Compilers
9 | 提供编译相关运行时
10 | Copyright (c) 2022, CYJB
11 | README.md
12 | LICENSE.txt
13 | en
14 | $(VersionPrefix)
15 | 1.0.23
16 | Cyjb.Compilers
17 | CYJB
18 | Compiler
19 | true
20 | snupkg
21 |
22 |
23 | ../CYJB_Code_Key.snk
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | True
33 |
34 |
35 |
36 |
37 | True
38 | True
39 | Resources.tt
40 |
41 |
42 |
43 |
44 | TextTemplatingFileGenerator
45 | Resources.cs
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Runtime/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013, CYJB
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice, this
11 | list of conditions and the following disclaimer in the documentation and/or
12 | other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/Runtime/Lexers/ContextData.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 表示词法分析中上下文的数据。
5 | ///
6 | public class ContextData
7 | {
8 | ///
9 | /// 初始的词法分析器上下文名称。
10 | ///
11 | public const string Initial = "Initial";
12 |
13 | ///
14 | /// 默认的词法分析上下文。
15 | ///
16 | public readonly static IReadOnlyDictionary Default =
17 | new Dictionary()
18 | {
19 | { Initial, new ContextData(0, Initial) }
20 | };
21 |
22 | ///
23 | /// 使用指定的上下文数据初始化 类的新实例。
24 | ///
25 | /// 上下文的索引。
26 | /// 上下文的标签。
27 | /// EOF 动作。
28 | /// EOF 动作的值。
29 | public ContextData(int index, string label, Delegate? eofAction = null, object? eofValue = null)
30 | {
31 | Index = index;
32 | Label = label;
33 | EofAction = eofAction;
34 | EofValue = eofValue;
35 | }
36 |
37 | ///
38 | /// 上下文的索引。
39 | ///
40 | public int Index { get; }
41 | ///
42 | /// 上下文的标签。
43 | ///
44 | public string Label { get; }
45 | ///
46 | /// 上下文的 EOF 动作。
47 | ///
48 | public Delegate? EofAction { get; }
49 | ///
50 | /// 上下文的 EOF 动作的值。
51 | ///
52 | public object? EofValue { get; }
53 | }
54 |
--------------------------------------------------------------------------------
/Runtime/Lexers/Core/BasicCore`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 表示基本的词法分析器核心。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | internal sealed class BasicCore : LexerCore
8 | where T : struct
9 | {
10 | ///
11 | /// 词法分析器的数据。
12 | ///
13 | private readonly LexerData lexerData;
14 | ///
15 | /// DFA 的状态列表。
16 | ///
17 | private readonly int[] states;
18 |
19 | ///
20 | /// 使用给定的词法分析器信息初始化 类的新实例。
21 | ///
22 | /// 要使用的词法分析器的数据。
23 | /// 词法分析控制器。
24 | public BasicCore(LexerData lexerData, LexerController controller) :
25 | base(lexerData.States, lexerData.Terminals, lexerData.ContainsBeginningOfLine, controller)
26 | {
27 | this.lexerData = lexerData;
28 | states = lexerData.States;
29 | }
30 |
31 | ///
32 | /// 读取输入流中的下一个词法单元并提升输入流的字符位置。
33 | ///
34 | /// DFA 的起始状态。
35 | /// 当前词法单元的起始位置。
36 | /// 词法单元读入是否成功。
37 | public override bool NextToken(int state, int start)
38 | {
39 | // 最后一次匹配的符号和文本索引。
40 | int lastAccept = -1, lastIndex = source.Index;
41 | int symbolStart = 0, symbolEnd = 0;
42 | while (true)
43 | {
44 | state = lexerData.NextState(state, source.Read());
45 | if (state == -1)
46 | {
47 | // 没有合适的转移,退出。
48 | break;
49 | }
50 | if (lexerData.GetSymbols(state, ref symbolStart, ref symbolEnd))
51 | {
52 | lastAccept = states[symbolStart];
53 | lastIndex = source.Index;
54 | // 使用最短匹配时,可以直接返回。
55 | if (lexerData.UseShortest && terminalData[lastAccept].UseShortest)
56 | {
57 | break;
58 | }
59 | }
60 | }
61 | if (lastAccept >= 0)
62 | {
63 | // 将流调整到与接受状态匹配的状态。
64 | DoAction(start, lastIndex, terminalData[lastAccept]);
65 | return true;
66 | }
67 | return false;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Runtime/Lexers/Core/BasicDebugCore.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 表示带有调试信息的基本的词法分析器核心。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | internal sealed class BasicDebugCore : LexerCore
8 | where T : struct
9 | {
10 | ///
11 | /// 词法分析器的数据。
12 | ///
13 | private readonly LexerData lexerData;
14 | ///
15 | /// DFA 的状态列表。
16 | ///
17 | private readonly int[] states;
18 |
19 | ///
20 | /// 使用给定的词法分析器信息初始化 类的新实例。
21 | ///
22 | /// 要使用的词法分析器的数据。
23 | /// 词法分析控制器。
24 | public BasicDebugCore(LexerData lexerData, LexerController controller) :
25 | base(lexerData.States, lexerData.Terminals, lexerData.ContainsBeginningOfLine, controller)
26 | {
27 | this.lexerData = lexerData;
28 | states = lexerData.States;
29 | }
30 |
31 | ///
32 | /// 读取输入流中的下一个词法单元并提升输入流的字符位置。
33 | ///
34 | /// DFA 的起始状态。
35 | /// 当前词法单元的起始位置。
36 | /// 词法单元读入是否成功。
37 | public override bool NextToken(int state, int start)
38 | {
39 | // 最后一次匹配的符号和文本索引。
40 | int startIndex = source.Index;
41 | int lastAccept = -1, lastIndex = source.Index;
42 | int symbolStart = 0, symbolEnd = 0;
43 | while (true)
44 | {
45 | state = lexerData.NextState(state, source.Read());
46 | if (state == -1)
47 | {
48 | // 没有合适的转移,退出。
49 | break;
50 | }
51 | if (lexerData.GetSymbols(state, ref symbolStart, ref symbolEnd))
52 | {
53 | lastAccept = states[symbolStart];
54 | lastIndex = source.Index;
55 | // 使用最短匹配时,可以直接返回。
56 | if (lexerData.UseShortest && terminalData[lastAccept].UseShortest)
57 | {
58 | break;
59 | }
60 | }
61 | }
62 | PrintReadedText();
63 | if (lastAccept >= 0)
64 | {
65 | // 将流调整到与接受状态匹配的状态。
66 | DoAction(start, lastIndex, terminalData[lastAccept]);
67 | Console.WriteLine(" Match {0}..{1} [{2}] {3}", startIndex, lastIndex, lastAccept,
68 | terminalData[lastAccept].Kind);
69 | return true;
70 | }
71 | else
72 | {
73 | Console.WriteLine(" Match none");
74 | }
75 | return false;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Runtime/Lexers/Core/LexerStateInfo.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 词法分析器的状态信息。
5 | ///
6 | class LexerStateInfo
7 | {
8 | ///
9 | /// 当前源文件索引。
10 | ///
11 | public int SourceIndex;
12 | ///
13 | /// 匹配的终结符起始索引(包含)。
14 | ///
15 | public int TerminalStart;
16 | ///
17 | /// 匹配的终结符结束索引(不包含)。
18 | ///
19 | public int TerminalEnd;
20 | }
21 |
--------------------------------------------------------------------------------
/Runtime/Lexers/DfaStateData.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// DFA 的状态数据。
5 | ///
6 | public static class DfaStateData
7 | {
8 | ///
9 | /// 表示无效的状态。
10 | ///
11 | public const int InvalidState = -1;
12 | ///
13 | /// 默认状态的偏移。
14 | ///
15 | public const int DefaultStateOffset = 1;
16 | ///
17 | /// 符号列表长度的偏移。
18 | ///
19 | public const int SymbolsLengthOffset = 2;
20 | ///
21 | /// 符号索引的偏移。
22 | ///
23 | public const int SymbolIndexOffset = 3;
24 | }
25 |
--------------------------------------------------------------------------------
/Runtime/Lexers/ILexerFactory`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 表示词法分析器的工厂。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | public interface ILexerFactory
8 | where T : struct
9 | {
10 | ///
11 | /// 创建词法分析器。
12 | ///
13 | /// 是否需要打印调试信息。
14 | /// 已创建的词法分析器。
15 | LexerTokenizer CreateTokenizer(bool debug = false);
16 |
17 | ///
18 | /// 创建词法分析运行器。
19 | ///
20 | /// 是否需要打印调试信息。
21 | /// 已创建的词法分析运行器。
22 | LexerRunner CreateRunner(bool debug = false);
23 | }
24 |
--------------------------------------------------------------------------------
/Runtime/Lexers/LexerFactory`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 表示词法分析器的工厂。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | /// 关于如何构造自己的词法分析器,可以参考我的博文
8 | ///
9 | /// 《C# 词法分析器(六)构造词法分析器》。
10 | ///
11 | /// 《C# 词法分析器(六)构造词法分析器》
12 | public sealed class LexerFactory : ILexerFactory
13 | where T : struct
14 | {
15 | ///
16 | /// 动作处理器。
17 | ///
18 | private static readonly Action> actionHandler =
19 | (Delegate action, LexerController controller) =>
20 | {
21 | ((Action>)action)(controller);
22 | };
23 |
24 | ///
25 | /// 词法分析器的数据。
26 | ///
27 | private readonly LexerData lexerData;
28 |
29 | ///
30 | /// 使用指定的词法分析器数据初始化 类的新实例。
31 | ///
32 | /// 词法分析器的数据。
33 | public LexerFactory(LexerData lexerData)
34 | {
35 | this.lexerData = lexerData;
36 | }
37 |
38 | ///
39 | /// 创建词法分析器。
40 | ///
41 | /// 是否需要打印调试信息。
42 | /// 已创建的词法分析器。
43 | public LexerTokenizer CreateTokenizer(bool debug = false)
44 | {
45 | LexerController controller = new()
46 | {
47 | ActionHandler = actionHandler
48 | };
49 | LexerCore core = LexerCore.Create(lexerData, controller, debug);
50 | controller.SetCore(core, lexerData.Contexts, lexerData.Rejectable);
51 | return new LexerTokenizer(core);
52 | }
53 |
54 | ///
55 | /// 创建词法分析运行器。
56 | ///
57 | /// 是否需要打印调试信息。
58 | /// 已创建的词法分析运行器。
59 | public LexerRunner CreateRunner(bool debug = false)
60 | {
61 | LexerController controller = new()
62 | {
63 | ActionHandler = actionHandler
64 | };
65 | LexerCore core = LexerCore.Create(lexerData, controller, debug);
66 | controller.SetCore(core, lexerData.Contexts, lexerData.Rejectable);
67 | return new LexerRunner(core);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Runtime/Lexers/LexerFactory`2.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 表示词法分析器的工厂。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | /// 词法分析控制器的类型。
8 | /// 关于如何构造自己的词法分析器,可以参考我的博文
9 | ///
10 | /// 《C# 词法分析器(六)构造词法分析器》。
11 | ///
12 | /// 《C# 词法分析器(六)构造词法分析器》
13 | public sealed class LexerFactory : ILexerFactory
14 | where T : struct
15 | where TController : LexerController, new()
16 | {
17 | ///
18 | /// 动作处理器。
19 | ///
20 | private static readonly Action> actionHandler =
21 | (Delegate action, LexerController controller) =>
22 | {
23 | ((Action)action)((TController)controller);
24 | };
25 |
26 | ///
27 | /// 词法分析器的数据。
28 | ///
29 | private readonly LexerData lexerData;
30 |
31 | ///
32 | /// 使用指定的词法分析器数据初始化 类的新实例。
33 | ///
34 | /// 词法分析器的数据。
35 | public LexerFactory(LexerData lexerData)
36 | {
37 | this.lexerData = lexerData;
38 | }
39 |
40 | ///
41 | /// 创建词法分析器。
42 | ///
43 | /// 是否需要打印调试信息。
44 | /// 已创建的词法分析器。
45 | public LexerTokenizer CreateTokenizer(bool debug = false)
46 | {
47 | TController controller = new()
48 | {
49 | ActionHandler = actionHandler
50 | };
51 | LexerCore core = LexerCore.Create(lexerData, controller, debug);
52 | controller.SetCore(core, lexerData.Contexts, lexerData.Rejectable);
53 | return new LexerTokenizer(core);
54 | }
55 |
56 | ///
57 | /// 创建词法分析运行器。
58 | ///
59 | /// 是否需要打印调试信息。
60 | /// 已创建的词法分析运行器。
61 | public LexerRunner CreateRunner(bool debug = false)
62 | {
63 | TController controller = new()
64 | {
65 | ActionHandler = actionHandler
66 | };
67 | LexerCore core = LexerCore.Create(lexerData, controller, debug);
68 | controller.SetCore(core, lexerData.Contexts, lexerData.Rejectable);
69 | return new LexerRunner(core);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Runtime/Lexers/RejectOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 拒绝匹配的选项。
5 | ///
6 | public enum RejectOptions
7 | {
8 | ///
9 | /// 拒绝当前匹配。
10 | ///
11 | Default,
12 | ///
13 | /// 拒绝当前状态的匹配。
14 | ///
15 | /// 会忽略当前状态的后续匹配,避免使用更短的字符串重复匹配相同状态。
16 | State,
17 | }
18 |
--------------------------------------------------------------------------------
/Runtime/Lexers/TerminalData`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 表示词法分析中终结符的数据。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | public sealed class TerminalData
8 | where T : struct
9 | {
10 | ///
11 | /// 使用指定的终结符信息初始化 类的新实例。
12 | ///
13 | /// 终结符的类型。
14 | /// 终结符的值。
15 | /// 终结符的动作。
16 | /// 向前看信息。
17 | /// 是否使用最短匹配。
18 | public TerminalData(T? kind = null, object? value = null, Delegate? action = null,
19 | int? trailing = null, bool useShortest = false)
20 | {
21 | Kind = kind;
22 | Value = value;
23 | Action = action;
24 | Trailing = trailing;
25 | UseShortest = useShortest;
26 | }
27 |
28 | ///
29 | /// 获取终结符的类型。
30 | ///
31 | public T? Kind { get; }
32 | ///
33 | /// 获取终结符的值。
34 | ///
35 | public object? Value { get; }
36 | ///
37 | /// 获取终结符的动作。
38 | ///
39 | public Delegate? Action { get; }
40 | ///
41 | /// 获取终结符的向前看信息。
42 | ///
43 | /// null 表示不是向前看符号,正数表示前面长度固定,
44 | /// 负数表示后面长度固定,0 表示长度不固定。
45 | public int? Trailing { get; }
46 | ///
47 | /// 获取设置是否使用终结符的最短匹配。
48 | ///
49 | /// 默认都会使用正则表达式的最长匹配,允许指定为使用最短匹配,
50 | /// 会在遇到第一个匹配时立即返回结果。
51 | public bool UseShortest { get; }
52 |
53 | ///
54 | /// 返回当前对象的字符串表示形式。
55 | ///
56 | /// 当前对象的字符串表示形式。
57 | public override string ToString()
58 | {
59 | string mark = UseShortest ? " (s)" : "";
60 | if (Trailing == null)
61 | {
62 | return $"[{Kind}]{mark}";
63 | }
64 | else
65 | {
66 | return $"[{Kind}] {Trailing}{mark}";
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Runtime/Lexers/TrailingType.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Lexers;
2 |
3 | ///
4 | /// 向前看符号的类型。
5 | ///
6 | public enum TrailingType
7 | {
8 | ///
9 | /// 没有使用向前看符号。
10 | ///
11 | None,
12 | ///
13 | /// 定长的向前看符号。
14 | ///
15 | Fixed,
16 | ///
17 | /// 变长的向前看符号。
18 | ///
19 | Variable
20 | }
21 |
--------------------------------------------------------------------------------
/Runtime/Parsers/EmptyTokenizer`1.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 |
3 | namespace Cyjb.Text;
4 |
5 | ///
6 | /// 提供空的词法分析器。
7 | ///
8 | /// 词法单元标识符的类型,一般是一个枚举类型。
9 | internal sealed class EmptyTokenizer : ITokenizer
10 | where T : struct
11 | {
12 | ///
13 | /// 空的词法分析器实例。
14 | ///
15 | public static readonly ITokenizer Empty = new EmptyTokenizer();
16 |
17 | ///
18 | /// 词法分析错误的事件。
19 | ///
20 | public event TokenizeErrorHandler? TokenizeError;
21 |
22 | ///
23 | /// 获取词法分析器的解析状态。
24 | ///
25 | public ParseStatus Status => ParseStatus.Finished;
26 | ///
27 | /// 获取或设置共享的上下文对象。
28 | ///
29 | /// 可以与外部(例如语法分析器)共享信息。
30 | public object? SharedContext { get; set; }
31 |
32 | ///
33 | /// 读取输入流中的下一个词法单元并提升输入流的字符位置。
34 | ///
35 | /// 输入流中的下一个词法单元。
36 | public Token Read()
37 | {
38 | return Token.GetEndOfFile(0);
39 | }
40 |
41 | ///
42 | /// 取消后续词法分析。
43 | ///
44 | public void Cancel() { }
45 |
46 | ///
47 | /// 重置词法分析的状态,允许在结束/取消后继续进行分析。
48 | ///
49 | public void Reset() { }
50 |
51 | #region IDisposable 成员
52 |
53 | ///
54 | /// 执行与释放或重置非托管资源相关的应用程序定义的任务。
55 | ///
56 | public void Dispose() { }
57 |
58 | #endregion // IDisposable 成员
59 |
60 | #region IEnumerable> 成员
61 |
62 | ///
63 | /// 返回一个循环访问集合的枚举器。
64 | ///
65 | /// 可用于循环访问集合的 。
66 | /// 在枚举的时候, 会不断的读出词法单元,
67 | /// 应当总是只使用一个枚举器。在使用多个枚举器时,他们之间会相互干扰,导致枚举值与期望的不同。
68 | /// 如果需要多次枚举,必须将词法单元缓存到数组中,再进行枚举。
69 | public IEnumerator> GetEnumerator()
70 | {
71 | yield break;
72 | }
73 |
74 | ///
75 | /// 返回一个循环访问集合的枚举器。
76 | ///
77 | /// 可用于循环访问集合的 。
78 | IEnumerator IEnumerable.GetEnumerator()
79 | {
80 | return GetEnumerator();
81 | }
82 |
83 | #endregion // IEnumerable> 成员
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/Runtime/Parsers/IParserFactory`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示语法分析器的工厂。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | public interface IParserFactory
8 | where T : struct
9 | {
10 | ///
11 | /// 创建语法分析器。
12 | ///
13 | /// 已创建的语法分析器。
14 | LRParser CreateParser();
15 | }
16 |
--------------------------------------------------------------------------------
/Runtime/Parsers/ParseOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 语法分析选项。
5 | ///
6 | public enum ParseOptions
7 | {
8 | ///
9 | /// 扫描到文件结尾。
10 | ///
11 | ScanToEOF,
12 | ///
13 | /// 扫描到匹配的语法单元。
14 | ///
15 | /// 对于 A* 这样的规则,会匹配到最后一个可能的 A。
16 | ScanToMatch,
17 | ///
18 | /// 扫描到首次匹配的语法单元。
19 | ///
20 | /// 对于 A* 这样的规则,只会匹配第一个 A。
21 | ScanToFirstMatch,
22 | }
23 |
--------------------------------------------------------------------------------
/Runtime/Parsers/ParserAction.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// LR 语法分析器的动作。
5 | ///
6 | public readonly record struct ParserAction
7 | {
8 | ///
9 | /// 获取表示接受的分析器动作。
10 | ///
11 | public static readonly ParserAction Accept = new(ParserActionType.Accept, 0);
12 | ///
13 | /// 获取表示错误的分析器动作。
14 | ///
15 | public static readonly ParserAction Error = new(ParserActionType.Error, 0);
16 |
17 | ///
18 | /// 返回表示归约的分析器动作。
19 | ///
20 | /// 归约使用的产生式编号。
21 | /// 表示归约的分析器动作。
22 | public static ParserAction Reduce(int index) => new(ParserActionType.Reduce, index);
23 | ///
24 | /// 返回表示移入的分析器动作。
25 | ///
26 | /// 移入后要压栈的状态编号。
27 | /// 表示移入的分析器动作。
28 | public static ParserAction Shift(int index) => new(ParserActionType.Shift, index);
29 |
30 | ///
31 | /// 使用指定的动作类型和索引初始化。
32 | ///
33 | /// 动作类型。
34 | /// 动作关联到的索引。
35 | private ParserAction(ParserActionType type, int index)
36 | {
37 | Type = type;
38 | Index = index;
39 | }
40 |
41 | ///
42 | /// 获取动作类型。
43 | ///
44 | public ParserActionType Type { get; init; }
45 | ///
46 | /// 获取动作关联到的索引。
47 | ///
48 | public int Index { get; init; }
49 |
50 | ///
51 | /// 返回当前对象的字符串表示。
52 | ///
53 | /// 当前对象的字符串表示。
54 | public override string ToString()
55 | {
56 | return Type switch
57 | {
58 | ParserActionType.Accept => "acc",
59 | ParserActionType.Shift => $"s{Index}",
60 | ParserActionType.Reduce => $"r{Index}",
61 | _ => "err",
62 | };
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Runtime/Parsers/ParserActionType.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// LR 语法分析器的动作类型。
5 | ///
6 | public enum ParserActionType
7 | {
8 | ///
9 | /// 错误动作。
10 | ///
11 | Error = 0,
12 | ///
13 | /// 移入动作。
14 | ///
15 | Shift = 1,
16 | ///
17 | /// 归约动作。
18 | ///
19 | Reduce = 2,
20 | ///
21 | /// 接受动作。
22 | ///
23 | Accept = 3,
24 | }
25 |
--------------------------------------------------------------------------------
/Runtime/Parsers/ParserData.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示 LR 语法分析器的数据。
5 | ///
6 | public sealed class ParserData
7 | {
8 | ///
9 | /// 表示无效的状态。
10 | ///
11 | public const int InvalidState = -1;
12 | }
13 |
--------------------------------------------------------------------------------
/Runtime/Parsers/ParserFactory`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示语法分析器的工厂。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | public sealed class ParserFactory : IParserFactory
8 | where T : struct
9 | {
10 | ///
11 | /// 动作处理器。
12 | ///
13 | private static readonly Func, object?> actionHandler =
14 | (Delegate action, ParserController controller) =>
15 | {
16 | return ((Func, object?>)action)(controller);
17 | };
18 |
19 | ///
20 | /// 语法分析器的数据。
21 | ///
22 | private readonly ParserData parserData;
23 |
24 | ///
25 | /// 使用指定的语法分析器数据初始化 类的新实例。
26 | ///
27 | /// 语法分析器的数据。
28 | public ParserFactory(ParserData parserData)
29 | {
30 | this.parserData = parserData;
31 | }
32 |
33 | ///
34 | /// 创建语法分析器。
35 | ///
36 | /// 已创建的语法分析器。
37 | public LRParser CreateParser()
38 | {
39 | ParserController controller = new();
40 | LRParser parser = new(parserData, controller);
41 | controller.Init(parserData, parser, actionHandler);
42 | return parser;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Runtime/Parsers/ParserFactory`2.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 表示语法分析器的工厂。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | /// 语法分析控制器的类型。
8 | public sealed class ParserFactory : IParserFactory
9 | where T : struct
10 | where TController : ParserController, new()
11 | {
12 | ///
13 | /// 动作处理器。
14 | ///
15 | private static readonly Func, object?> actionHandler =
16 | (Delegate action, ParserController controller) =>
17 | {
18 | return ((Func)action)((TController)controller);
19 | };
20 |
21 | ///
22 | /// 语法分析器的数据。
23 | ///
24 | private readonly ParserData parserData;
25 |
26 | ///
27 | /// 使用指定的语法分析器数据初始化 类的新实例。
28 | ///
29 | /// 语法分析器的数据。
30 | public ParserFactory(ParserData parserData)
31 | {
32 | this.parserData = parserData;
33 | }
34 |
35 | ///
36 | /// 创建语法分析器。
37 | ///
38 | /// 已创建的语法分析器。
39 | public LRParser CreateParser()
40 | {
41 | TController controller = new();
42 | LRParser parser = new(parserData, controller);
43 | controller.Init(parserData, parser, actionHandler);
44 | return parser;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Runtime/Parsers/ProductionAction.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 提供产生式数据的预置动作。
5 | ///
6 | public sealed class ProductionAction
7 | {
8 | ///
9 | /// 供 使用的动作。
10 | ///
11 | public static readonly Delegate Optional = () => "OptionalAction";
12 | ///
13 | /// 供 和 使用的动作。
14 | ///
15 | public static readonly Delegate More = () => "MoreAction";
16 | }
17 |
--------------------------------------------------------------------------------
/Runtime/Parsers/ProductionData`1.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Text;
3 |
4 | namespace Cyjb.Compilers.Parsers;
5 |
6 | ///
7 | /// 表示产生式的数据。
8 | ///
9 | /// 词法单元标识符的类型,一般是一个枚举类型。
10 | public sealed class ProductionData
11 | where T : struct
12 | {
13 | ///
14 | /// 产生式体的大小。
15 | ///
16 | [DebuggerBrowsable(DebuggerBrowsableState.Never)]
17 | private readonly int bodySize;
18 |
19 | ///
20 | /// 使用产生式的数据初始化 类的新实例。
21 | ///
22 | /// 产生式头的索引。
23 | /// 产生式头。
24 | /// 产生式对应的动作。
25 | /// 产生式体。
26 | public ProductionData(int headIndex, T head, Delegate? action, params T[] body)
27 | {
28 | HeadIndex = headIndex;
29 | Head = head;
30 | Action = action;
31 | Body = body;
32 | bodySize = body.Length;
33 | }
34 |
35 | ///
36 | /// 获取产生式头的索引。
37 | ///
38 | /// 产生式头的索引。
39 | public int HeadIndex { get; }
40 | ///
41 | /// 获取产生式头。
42 | ///
43 | /// 产生式头。
44 | public T Head { get; }
45 | ///
46 | /// 获取产生式对应的动作。
47 | ///
48 | /// 产生式对应的动作。
49 | public Delegate? Action { get; }
50 | ///
51 | /// 获取产生式体的大小。
52 | ///
53 | public int BodySize => bodySize;
54 | ///
55 | /// 获取产生式体。
56 | ///
57 | /// 产生式体。
58 | public T[] Body { get; }
59 |
60 | ///
61 | /// 返回当前对象的字符串表示形式。
62 | ///
63 | /// 当前对象的字符串表示形式。
64 | public override string ToString()
65 | {
66 | StringBuilder text = new();
67 | text.Append(Head);
68 | text.Append(" ->");
69 | if (bodySize == 0)
70 | {
71 | text.Append(" ε");
72 | }
73 | else
74 | {
75 | foreach (T item in Body)
76 | {
77 | text.Append(' ');
78 | text.Append(item);
79 | }
80 | }
81 | return text.ToString();
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Runtime/Parsers/SymbolOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Compilers.Parsers;
2 |
3 | ///
4 | /// 符号选项。
5 | ///
6 | public enum SymbolOptions
7 | {
8 | ///
9 | /// 无选项。
10 | ///
11 | None,
12 | ///
13 | /// 可选的符号,可能出现 0 或 1 次。
14 | ///
15 | Optional,
16 | ///
17 | /// 允许出现 1 或更多次。
18 | ///
19 | OneOrMore,
20 | ///
21 | /// 允许出现 0 或更多次。
22 | ///
23 | ZeroOrMore,
24 | }
25 |
--------------------------------------------------------------------------------
/Runtime/README.md:
--------------------------------------------------------------------------------
1 | Cyjb.Compilers.Runtime
2 | ====
3 |
4 | [](https://www.nuget.org/packages/Cyjb.Compilers.Runtime)
5 | [](https://codecov.io/gh/CYJB/Cyjb.Compilers)
6 |
7 | 提供编译相关运行时,基于 .NET 6。
8 |
9 | 本项目包括一些与编译相关的基础接口,用于运行词法分析器和语法分析器。
10 |
11 | 详细的类库文档,请参见 [Wiki](https://github.com/CYJB/Cyjb.Compilers/wiki)。
12 |
13 | 欢迎访问我的[博客](http://www.cnblogs.com/cyjb/)获取更多信息。
14 |
15 |
--------------------------------------------------------------------------------
/Runtime/Resources.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CYJB/Cyjb.Compilers/59a4272bfac4c9b9bf0447a869fb7e3f68480e6f/Runtime/Resources.cs
--------------------------------------------------------------------------------
/Runtime/Resources.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="$(PkgCyjb)\content\ResourcesTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/Runtime/Text/ITokenParser`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Text;
2 |
3 | ///
4 | /// 表示语法分析错误的事件处理器。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | /// 出现错误的语法分析器。
8 | /// 错误信息
9 | public delegate void TokenParseErrorHandler(ITokenParser parser, TokenParseError error)
10 | where T : struct;
11 |
12 |
13 | ///
14 | /// 表示语法分析器。
15 | ///
16 | /// 词法单元标识符的类型,一般是一个枚举类型。
17 | public interface ITokenParser : IDisposable
18 | where T : struct
19 | {
20 | ///
21 | /// 语法分析错误的事件。
22 | ///
23 | event TokenParseErrorHandler? ParseError;
24 | ///
25 | /// 获取语法分析器的解析状态。
26 | ///
27 | ParseStatus Status { get; }
28 | ///
29 | /// 获取或设置共享的上下文对象。
30 | ///
31 | /// 可以与外部(例如词法分析器)共享信息,只能够在首次调用 前设置。
32 | object? SharedContext { get; set; }
33 |
34 | ///
35 | /// 使用默认的目标类型分析当前词法单元序列。
36 | ///
37 | /// 语法分析的结果。
38 | public abstract ParserNode Parse();
39 |
40 | ///
41 | /// 使用指定的目标类型分析当前词法单元序列。
42 | ///
43 | /// 目标类型。
44 | /// 语法分析的结果。
45 | public abstract ParserNode Parse(T target);
46 |
47 | ///
48 | /// 取消后续语法分析。
49 | ///
50 | void Cancel();
51 |
52 | ///
53 | /// 重置语法分析的状态,允许在结束/取消后继续进行分析。
54 | ///
55 | void Reset();
56 | }
57 |
--------------------------------------------------------------------------------
/Runtime/Text/ITokenizer`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Text;
2 |
3 | ///
4 | /// 表示词法分析错误的事件处理器。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | /// 出现错误的词法分析器。
8 | /// 错误信息
9 | public delegate void TokenizeErrorHandler(ITokenizer tokenizer, TokenizeError error)
10 | where T : struct;
11 |
12 | ///
13 | /// 表示一个词法分析器。
14 | ///
15 | ///
16 | /// 词法单元标识符的类型,一般是一个枚举类型。
17 | public interface ITokenizer : IDisposable, IEnumerable>
18 | where T : struct
19 | {
20 | ///
21 | /// 词法分析错误的事件。
22 | ///
23 | event TokenizeErrorHandler? TokenizeError;
24 | ///
25 | /// 获取词法分析器的解析状态。
26 | ///
27 | ParseStatus Status { get; }
28 | ///
29 | /// 获取或设置共享的上下文对象。
30 | ///
31 | /// 可以与外部(例如语法分析器)共享信息,只能够在首次调用 前设置。
32 | object? SharedContext { get; set; }
33 |
34 | ///
35 | /// 读取输入流中的下一个词法单元并提升输入流的字符位置。
36 | ///
37 | /// 输入流中的下一个词法单元。
38 | Token Read();
39 |
40 | ///
41 | /// 取消后续词法分析。
42 | ///
43 | void Cancel();
44 |
45 | ///
46 | /// 重置词法分析的状态,允许在结束/取消后继续进行分析。
47 | ///
48 | void Reset();
49 | }
50 |
--------------------------------------------------------------------------------
/Runtime/Text/MissingTokenError.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using Cyjb.Compilers;
3 |
4 | namespace Cyjb.Text;
5 |
6 | ///
7 | /// 表示缺失词法单元的错误。
8 | ///
9 | /// 语法节点标识符的类型,必须是一个枚举类型。
10 | public class MissingTokenError : TokenParseError
11 | where T : struct
12 | {
13 | ///
14 | /// 缺失的词法单元。
15 | ///
16 | [DebuggerBrowsable(DebuggerBrowsableState.Never)]
17 | private readonly Token token;
18 |
19 | ///
20 | /// 使用缺失的词法单元初始化 类的新实例。
21 | ///
22 | /// 缺失的词法单元。
23 | public MissingTokenError(Token token)
24 | {
25 | this.token = token;
26 | }
27 |
28 | ///
29 | /// 获取缺失的词法单元类型。
30 | ///
31 | public T Missing => token.Kind;
32 |
33 | ///
34 | /// 获取语法分析错误的范围。
35 | ///
36 | /// 语法分析错误的范围。
37 | public override TextSpan Span => token.Span;
38 |
39 | ///
40 | /// 返回当前对象是否等于同一类型的另一对象。
41 | ///
42 | /// 要比较的对象。
43 | /// 如果当前对象等于 ,则为 true;否则为 false。
44 | public override bool Equals(TokenParseError? other)
45 | {
46 | if (other is MissingTokenError error)
47 | {
48 | return token == error.token;
49 | }
50 | else
51 | {
52 | return false;
53 | }
54 | }
55 |
56 | ///
57 | /// 返回当前对象的哈希值。
58 | ///
59 | /// 当前对象的哈希值。
60 | public override int GetHashCode()
61 | {
62 | return token.GetHashCode();
63 | }
64 |
65 | ///
66 | /// 返回当前对象的字符串表示形式。
67 | ///
68 | /// 当前对象的字符串表示形式。
69 | public override string ToString()
70 | {
71 | return Resources.MissingToken(Token.GetDisplayName(token.Kind), Span);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Runtime/Text/ParseStatus.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Text;
2 |
3 | ///
4 | /// 词法或语法分析器的解析状态。
5 | ///
6 | public enum ParseStatus
7 | {
8 | ///
9 | /// 已准备好解析。
10 | ///
11 | Ready,
12 | ///
13 | /// 已解析完毕。
14 | ///
15 | Finished,
16 | ///
17 | /// 已取消解析。
18 | ///
19 | Cancelled
20 | }
21 |
--------------------------------------------------------------------------------
/Runtime/Text/ParserNode`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Text;
2 |
3 | ///
4 | /// 表示语法节点。
5 | ///
6 | /// 语法节点标识符的类型,一般是一个枚举类型。
7 | public sealed class ParserNode
8 | where T : struct
9 | {
10 | ///
11 | /// 使用指定的词法单元初始化 类的新实例。
12 | ///
13 | /// 初始化使用的词法单元。
14 | public ParserNode(Token token)
15 | {
16 | Kind = token.Kind;
17 | Text = token.Text;
18 | Span = token.Span;
19 | Value = token.Value;
20 | }
21 |
22 | ///
23 | /// 使用指定的语法节点信息初始化 类的新实例。
24 | ///
25 | /// 语法节点的类型。
26 | /// 语法节点的范围。
27 | public ParserNode(T kind, TextSpan span)
28 | {
29 | Kind = kind;
30 | Text = StringView.Empty;
31 | Span = span;
32 | }
33 |
34 | ///
35 | /// 获取语法节点的类型。
36 | ///
37 | public T Kind { get; init; }
38 | ///
39 | /// 获取语法节点的文本(仅终结符包含文本,非终结符为空字符串)。
40 | ///
41 | public StringView Text { get; init; }
42 | ///
43 | /// 获取语法节点的范围。
44 | ///
45 | public TextSpan Span { get; init; }
46 | ///
47 | /// 获取语法节点的值。
48 | ///
49 | public object? Value { get; internal set; }
50 | ///
51 | /// 获取当前语法节点是否是由错误恢复逻辑生成的。
52 | ///
53 | public bool IsMissing { get; init; } = false;
54 | ///
55 | /// 获取当前语法节点前被跳过的词法单元列表。
56 | ///
57 | public Token[] SkippedTokens { get; init; } = Array.Empty>();
58 | ///
59 | /// 获取当前语法节点是否包含错误。
60 | ///
61 | public bool ContainsError => IsMissing || SkippedTokens.Length > 0;
62 |
63 | ///
64 | /// 返回当前对象的字符串表示形式。
65 | ///
66 | /// 当前对象的字符串表示形式。
67 | public override string ToString()
68 | {
69 | return $"{Kind} at {Span}";
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Runtime/Text/TokenDisplayNameAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Text;
2 |
3 | ///
4 | /// 表示词法单元类型的显示名称。
5 | ///
6 | [AttributeUsage(AttributeTargets.Field)]
7 | public sealed class TokenDisplayNameAttribute : Attribute
8 | {
9 | ///
10 | /// 使用指定的显示名称初始化 类的新实例。
11 | ///
12 | /// 词法单元类型的显示名称。
13 | public TokenDisplayNameAttribute(string displayName)
14 | {
15 | DisplayName = displayName;
16 | }
17 |
18 | ///
19 | /// 获取词法单元类型的显示名称。
20 | ///
21 | public string DisplayName { get; }
22 | }
23 |
--------------------------------------------------------------------------------
/Runtime/Text/TokenSpanComparer`1.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Text;
2 |
3 | ///
4 | /// 表示一个词法单元的位置比较器。
5 | ///
6 | /// 词法单元标识符的类型,一般是一个枚举类型。
7 | internal class TokenSpanComparer : IComparer>
8 | where T : struct
9 | {
10 | ///
11 | /// 词法单元的位置比较器实例。
12 | ///
13 | public static readonly TokenSpanComparer Instance = new();
14 |
15 | ///
16 | /// 比较两个对象并返回一个值,指示一个对象小于、等于还是大于另一个对象。
17 | ///
18 | /// 要比较的第一个对象。
19 | /// 要比较的第二个对象。
20 | /// 一个有符号整数,指示 和 的相对值。
21 | public int Compare(Token? x, Token? y)
22 | {
23 | if (ReferenceEquals(x, y))
24 | {
25 | return 0;
26 | }
27 | else if (x is null)
28 | {
29 | return -1;
30 | }
31 | else if (y is null)
32 | {
33 | return 1;
34 | }
35 | return x.Span.CompareTo(y.Span);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Runtime/Text/Token`1.DisplayName.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace Cyjb.Text;
4 |
5 | public partial class Token
6 | {
7 | ///
8 | /// 词法单元类型的显示名称映射表。
9 | ///
10 | private static readonly Lazy> displayNames = new(() =>
11 | {
12 | Dictionary result = new();
13 | try
14 | {
15 | foreach (FieldInfo field in typeof(T).GetFields())
16 | {
17 | TokenDisplayNameAttribute? attr = field.GetCustomAttribute();
18 | if (attr != null && Enum.TryParse(field.Name, out T value))
19 | {
20 | result[value] = attr.DisplayName;
21 | }
22 | }
23 | }
24 | catch (ArgumentException)
25 | {
26 | // T 不是枚举。
27 | }
28 | return result;
29 | });
30 |
31 | ///
32 | /// 返回指定词法单元类型的显示名称。
33 | ///
34 | /// 要检查的词法单元类型。
35 | /// 指定词法单元类型的显示名称。
36 | public static string GetDisplayName(T kind)
37 | {
38 | if (EqualityComparer.Default.Equals(kind, EndOfFile))
39 | {
40 | return "<>";
41 | }
42 | if (displayNames.Value.TryGetValue(kind, out string? name))
43 | {
44 | return name;
45 | }
46 | else
47 | {
48 | return kind.ToString()!;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Runtime/Text/Utils.cs:
--------------------------------------------------------------------------------
1 | namespace Cyjb.Text;
2 |
3 | ///
4 | /// 提供工具方法。
5 | ///
6 | internal static class Utils
7 | {
8 | ///
9 | /// 换行的字符。
10 | ///
11 | public static char[] NewLineChars = { '\r', '\n' };
12 |
13 | ///
14 | /// 返回指定的字符是否是换行符。
15 | ///
16 | public static bool IsLineBreak(char ch)
17 | {
18 | return ch is '\n' or '\r' or '\u0085' or '\u2028' or '\u2029';
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/TestCompilers/Calc.cs:
--------------------------------------------------------------------------------
1 | namespace TestCompilers;
2 |
3 | public enum Calc { Id, Add, Sub, Mul, Div, Pow, LBrace, RBrace, E }
4 |
--------------------------------------------------------------------------------
/TestCompilers/CompilerTemplate.t4:
--------------------------------------------------------------------------------
1 | <#
2 | /**
3 | * 生成词法分析器或语法分析器的实现。
4 | */
5 | #>
6 | <#@ template language="C#" hostspecific="true" #>
7 | <#@output extension=".designed.cs" encoding="UTF-8"#>
8 | <#@ assembly name="System.Core" #>
9 | <#@ assembly name="System.Runtime" #>
10 | <#@ assembly name="EnvDTE" #>
11 | <#@ assembly name="VSLangProj" #>
12 | <#@ import namespace="EnvDTE" #>
13 | <#@ import namespace="System" #>
14 | <#@ import namespace="System.CodeDom.Compiler" #>
15 | <#@ import namespace="System.Diagnostics" #>
16 | <#@ import namespace="System.IO" #>
17 | <#@ import namespace="System.Text.RegularExpressions" #>
18 | <#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
19 | <#
20 | string toolPath = Host.ResolveAssemblyReference(@"Generator\bin\Release\net6.0\Generator.dll");
21 | string filePath = Host.TemplateFile.Replace(".tt", ".cs");
22 | try
23 | {
24 | using System.Diagnostics.Process myProcess = new();
25 | myProcess.StartInfo.UseShellExecute = false;
26 | myProcess.StartInfo.RedirectStandardOutput = true;
27 | myProcess.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;
28 | myProcess.StartInfo.FileName = "dotnet";
29 | myProcess.StartInfo.Arguments = $"\"{Path.GetFullPath(toolPath)}\" \"{Path.GetFullPath(filePath)}\"";
30 | myProcess.StartInfo.CreateNoWindow = true;
31 | myProcess.Start();
32 | string content = myProcess.StandardOutput.ReadToEnd();
33 | myProcess.WaitForExit();
34 |
35 | if (content.StartsWith(Path.GetFileName(filePath)))
36 | {
37 | // 包含异常
38 | string[] lines = content.Trim().Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
39 | Regex errorRegex = new Regex(@"^.+\((\d+),(\d+)\): (.+)$");
40 | foreach(string line in lines)
41 | {
42 | Match match = errorRegex.Match(line);
43 | if (match.Success) {
44 | string lineNum = match.Groups[1].Captures[0].Value;
45 | string colNum = match.Groups[2].Captures[0].Value;
46 | string message = match.Groups[3].Captures[0].Value;
47 | Errors.Add(new CompilerError(filePath, int.Parse(lineNum), int.Parse(colNum), "", message));
48 | }
49 | }
50 | Write("// 生成异常");
51 | } else {
52 | Write(content);
53 | }
54 | }
55 | catch (Exception e)
56 | {
57 | Error($"执行 {toolPath} 失败:{e.Message}");
58 | }
59 | #>
60 |
61 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/LexerRunnerContext.cs:
--------------------------------------------------------------------------------
1 | namespace TestCompilers.Lexers;
2 |
3 | internal class LexerRunnerContext
4 | {
5 | public object? Result { get; set; }
6 | }
7 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Shortest/TestShortestLexer1.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 |
3 | namespace TestCompilers.Lexers;
4 |
5 | ///
6 | /// 用于测试简单最短匹配的词法分析器。
7 | ///
8 | [LexerSymbol("ab+", Kind = TestKind.A, UseShortest = true)]
9 | internal partial class TestShortestLexer1 : LexerController
10 | {
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Shortest/TestShortestLexer1.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Shortest/TestShortestLexer2.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 |
3 | namespace TestCompilers.Lexers;
4 |
5 | ///
6 | /// 用于测试向前看最短匹配的词法分析器。
7 | ///
8 | [LexerSymbol("a.+/b", Kind = TestKind.A, UseShortest = true)]
9 | internal partial class TestShortestLexer2 : LexerController
10 | {
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Shortest/TestShortestLexer2.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Shortest/TestShortestLexer3.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 |
3 | namespace TestCompilers.Lexers;
4 |
5 | ///
6 | /// 用于测试可拒绝最短匹配的词法分析器。
7 | ///
8 | [LexerRejectable]
9 | internal partial class TestShortestLexer3 : LexerController
10 | {
11 | [LexerSymbol("ab+", Kind = TestKind.A, UseShortest = true)]
12 | public void TestAction()
13 | {
14 | if (Text.Length < 4)
15 | {
16 | Reject();
17 | }
18 | else
19 | {
20 | Accept();
21 | }
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Shortest/TestShortestLexer3.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Shortest/TestShortestLexer4.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 |
3 | namespace TestCompilers.Lexers;
4 |
5 | ///
6 | /// 用于测试向前看+可拒绝最短匹配的词法分析器。
7 | ///
8 | [LexerRejectable]
9 | internal partial class TestShortestLexer4 : LexerController
10 | {
11 | [LexerSymbol("a.+/b", Kind = TestKind.A, UseShortest = true)]
12 | public void TestAction()
13 | {
14 | if (Text.Length < 4)
15 | {
16 | Reject();
17 | }
18 | else
19 | {
20 | Accept();
21 | }
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Shortest/TestShortestLexer4.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestCalcLexer.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 |
3 | namespace TestCompilers.Lexers;
4 |
5 | ///
6 | /// 用于单元测试的计算器控制器。
7 | ///
8 | [LexerSymbol("\\+", Kind = Calc.Add)]
9 | [LexerSymbol("\\-", Kind = Calc.Sub)]
10 | [LexerSymbol("\\*", Kind = Calc.Mul)]
11 | [LexerSymbol("\\/", Kind = Calc.Div)]
12 | [LexerSymbol("\\^", Kind = Calc.Pow)]
13 | [LexerSymbol("\\(", Kind = Calc.LBrace)]
14 | [LexerSymbol("\\)", Kind = Calc.RBrace)]
15 | [LexerSymbol("\\s")]
16 | internal partial class TestCalcLexer : LexerController
17 | {
18 | ///
19 | /// 数字的终结符定义。
20 | ///
21 | [LexerSymbol("[0-9]+", Kind = Calc.Id)]
22 | public void DigitAction()
23 | {
24 | Accept(double.Parse(Text.AsSpan()));
25 | }
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestCalcLexer.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestCalcRunnerLexer.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Cyjb.Compilers.Lexers;
3 |
4 | namespace TestCompilers.Lexers;
5 |
6 | ///
7 | /// 用于单元测试的计算器控制器。
8 | ///
9 | [LexerSymbol("\\s")]
10 | internal partial class TestCalcRunnerLexer : LexerController
11 | {
12 | private readonly StringBuilder text = new();
13 |
14 |
15 | ///
16 | /// 数字的终结符定义。
17 | ///
18 | [LexerSymbol("[0-9]+", Kind = Calc.Id)]
19 | public void DigitAction()
20 | {
21 | text.Append(Text.AsSpan());
22 | }
23 |
24 | ///
25 | /// 操作符的动作。
26 | ///
27 | [LexerSymbol("\\+", Kind = Calc.Add)]
28 | [LexerSymbol("\\-", Kind = Calc.Sub)]
29 | [LexerSymbol("\\*", Kind = Calc.Mul)]
30 | [LexerSymbol("\\/", Kind = Calc.Div)]
31 | [LexerSymbol("\\^", Kind = Calc.Pow)]
32 | [LexerSymbol("\\(", Kind = Calc.LBrace)]
33 | [LexerSymbol("\\)", Kind = Calc.RBrace)]
34 | public void OperatorAction()
35 | {
36 | text.Append(Text.AsSpan());
37 | }
38 |
39 | ///
40 | /// 文件结束的动作。
41 | ///
42 | [LexerSymbol("<>")]
43 | public void EofAction()
44 | {
45 | ((LexerRunnerContext)SharedContext!).Result = text.ToString();
46 | }
47 |
48 | ///
49 | /// 已加载源读取器。
50 | ///
51 | protected override void SourceLoaded()
52 | {
53 | base.SourceLoaded();
54 | text.Clear();
55 | }
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestCalcRunnerLexer.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestEscapeStrLexer.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Text;
3 | using Cyjb.Compilers.Lexers;
4 | using Cyjb.Text;
5 |
6 | namespace TestCompilers.Lexers;
7 |
8 | ///
9 | /// 用于单元测试的转义字符串控制器。
10 | ///
11 | [LexerContext("str")]
12 | [LexerContext("vstr")]
13 | public partial class TestEscapeStrLexer : LexerController
14 | {
15 | private const string CtxStr = "str";
16 | private const string CtxVstr = "vstr";
17 |
18 | ///
19 | /// 当前起始索引。
20 | ///
21 | private int curStart;
22 | ///
23 | /// 处理后的文本。
24 | ///
25 | private readonly StringBuilder decodedText = new();
26 |
27 | [LexerSymbol(@"\""")]
28 | public void BeginStrAction()
29 | {
30 | PushContext(CtxStr);
31 | curStart = Start;
32 | decodedText.Clear();
33 | }
34 |
35 | [LexerSymbol(@"@\""")]
36 | public void BeginVstrAction()
37 | {
38 | PushContext(CtxVstr);
39 | curStart = Start;
40 | decodedText.Clear();
41 | }
42 |
43 | [LexerSymbol(@"\""", Kind = Str.Str)]
44 | public void EndAction()
45 | {
46 | PopContext();
47 | Start = curStart;
48 | Text = decodedText.ToString();
49 | }
50 |
51 | [LexerSymbol(@"\\u[0-9]{4}")]
52 | [LexerSymbol(@"\\x[0-9]{2}")]
53 | public void HexEscapeAction()
54 | {
55 | decodedText.Append((char)int.Parse(Text.AsSpan(2), NumberStyles.HexNumber));
56 | }
57 |
58 | [LexerSymbol(@"\\n")]
59 | public void EscapeLFAction()
60 | {
61 | decodedText.Append('\n');
62 | }
63 |
64 | [LexerSymbol(@"\\\""")]
65 | public void EscapeQuoteAction()
66 | {
67 | decodedText.Append('\"');
68 | }
69 |
70 | [LexerSymbol(@"\\r")]
71 | public void EscapeCRAction()
72 | {
73 | decodedText.Append('\r');
74 | }
75 |
76 | [LexerSymbol(@"<*>.")]
77 | public void CopyAction()
78 | {
79 | StringBuilderUtil.Append(decodedText, Text);
80 | }
81 |
82 | [LexerSymbol(@"\""\""")]
83 | public void VstrQuoteAction()
84 | {
85 | decodedText.Append('"');
86 | }
87 | }
88 |
89 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestEscapeStrLexer.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestProductionLexer.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 |
3 | namespace TestCompilers.Lexers;
4 |
5 | ///
6 | /// 用于单元测试的计算器控制器。
7 | ///
8 | [LexerSymbol(@"\d+|\w[\w\d]*", Kind = ProductionKind.Id)]
9 | [LexerSymbol(@"\(", Kind = ProductionKind.LBrace)]
10 | [LexerSymbol(@"\)", Kind = ProductionKind.RBrace)]
11 | [LexerSymbol(@"\+", Kind = ProductionKind.Plus)]
12 | [LexerSymbol(@"\*", Kind = ProductionKind.Star)]
13 | [LexerSymbol(@"\?", Kind = ProductionKind.Question)]
14 | [LexerSymbol(@"\s")]
15 | public partial class TestProductionLexer : LexerController
16 | { }
17 |
18 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestProductionLexer.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestStrLexer.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 |
3 | namespace TestCompilers.Lexers;
4 |
5 | public enum Str { Str }
6 |
7 | ///
8 | /// 用于单元测试的字符串控制器。
9 | ///
10 | [LexerRegex("regular_char", @"[^""\\\n\r\u0085\u2028\u2029]|(\\.)")]
11 | [LexerRegex("regular_literal", @"\""{regular_char}*\""")]
12 | [LexerRegex("verbatim_char", @"[^""]|\""\""")]
13 | [LexerRegex("verbatim_literal", @"@\""{verbatim_char}*\""")]
14 | [LexerSymbol("{regular_literal}|{verbatim_literal}", Kind = Str.Str)]
15 | public partial class TestStrLexer : LexerController
16 | {
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestStrLexer.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestSymbolValueLexer.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 |
4 | namespace TestCompilers.Lexers;
5 |
6 | ///
7 | /// 测试词法单元的值。
8 | ///
9 | public partial class TestSymbolValueLexer : LexerController
10 | {
11 | [LexerSymbol("[0-9]+", Kind = Calc.Id, Value = 101)]
12 | public void DigitAction()
13 | {
14 | Assert.AreEqual(101, Value);
15 | Accept((int)Value! + 10);
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/TestSymbolValueLexer.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Trailing/TestTrailingLexer1.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using Cyjb.Compilers.Lexers;
3 |
4 | namespace TestCompilers.Lexers;
5 |
6 | ///
7 | /// 用于测试前面固定长度向前看的词法分析器。
8 | ///
9 | [LexerSymbol("ab/c", Kind = TestKind.A)]
10 | [LexerSymbol(".", RegexOptions.Singleline, Kind = TestKind.B)]
11 | internal partial class TestTrailingLexer1 : LexerController
12 | {
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Trailing/TestTrailingLexer1.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Trailing/TestTrailingLexer2.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using Cyjb.Compilers.Lexers;
3 |
4 | namespace TestCompilers.Lexers;
5 |
6 | ///
7 | /// 用于测试后面固定长度向前看的词法分析器。
8 | ///
9 | [LexerSymbol("a+/b", Kind = TestKind.A)]
10 | [LexerSymbol(".", RegexOptions.Singleline, Kind = TestKind.B)]
11 | internal partial class TestTrailingLexer2 : LexerController
12 | {
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Trailing/TestTrailingLexer2.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Trailing/TestTrailingLexer3.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using Cyjb.Compilers.Lexers;
3 |
4 | namespace TestCompilers.Lexers;
5 |
6 | ///
7 | /// 用于测试非固定长度向前看的词法分析器。
8 | ///
9 | [LexerSymbol("a+/b*c", Kind = TestKind.A)]
10 | [LexerSymbol(".", RegexOptions.Singleline, Kind = TestKind.B)]
11 | internal partial class TestTrailingLexer3 : LexerController
12 | {
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Trailing/TestTrailingLexer3.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Trailing/TestTrailingLexerEOL.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using Cyjb.Compilers.Lexers;
3 |
4 | namespace TestCompilers.Lexers;
5 |
6 | ///
7 | /// 用于测试向前看行尾的词法分析器。
8 | ///
9 | [LexerSymbol("a$", Kind = TestKind.A)]
10 | [LexerSymbol(".", RegexOptions.Singleline, Kind = TestKind.B)]
11 | internal partial class TestTrailingLexerEOL : LexerController
12 | {
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/Trailing/TestTrailingLexerEOL.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="..\..\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/UnitTestLexer.cancel.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 | using Cyjb.Text;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace TestCompilers.Lexers;
6 |
7 | public partial class UnitTestLexer
8 | {
9 | ///
10 | /// 对取消词法分析进行测试。
11 | ///
12 | [TestMethod]
13 | public void TestCancel()
14 | {
15 | LexerTokenizer tokenizer = TestCalcLexer.Factory.CreateTokenizer();
16 | tokenizer.Load("1 + 20 * 3 / 4*(5+6)");
17 |
18 | Assert.AreEqual(ParseStatus.Ready, tokenizer.Status);
19 | Assert.AreEqual(new Token(Calc.Id, "1", new TextSpan(0, 1), 1), tokenizer.Read());
20 | Assert.AreEqual(new Token(Calc.Add, "+", new TextSpan(2, 3)), tokenizer.Read());
21 | Assert.AreEqual(new Token(Calc.Id, "20", new TextSpan(4, 6), 20), tokenizer.Read());
22 | tokenizer.Cancel();
23 | Assert.AreEqual(ParseStatus.Cancelled, tokenizer.Status);
24 | Assert.AreEqual(Token.GetEndOfFile(6), tokenizer.Read());
25 | Assert.AreEqual(Token.GetEndOfFile(6), tokenizer.Read());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/UnitTestLexer.merge.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Cyjb.Compilers.Lexers;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace TestCompilers.Lexers;
6 |
7 | public partial class UnitTestLexer
8 | {
9 | ///
10 | /// 测试合并终结符。
11 | ///
12 | [TestMethod]
13 | public void TestMerge()
14 | {
15 | // 简单匹配。
16 | Lexer lexer = new();
17 | lexer.DefineSymbol(@"a").Kind(TestKind.A);
18 | lexer.DefineSymbol(@"b").Kind(TestKind.A);
19 | lexer.DefineSymbol(@"c").Kind(TestKind.A);
20 | LexerData data = lexer.GetData();
21 |
22 | // 终结符会被合并成一个。
23 | Assert.AreEqual(1, data.Terminals.Length);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/UnitTestLexer.token.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 | using Cyjb.Text;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace TestCompilers.Lexers;
6 |
7 | public partial class UnitTestLexer
8 | {
9 | ///
10 | /// 测试文本是可变的。
11 | ///
12 | [TestMethod]
13 | public void TestMutableText()
14 | {
15 | Lexer lexer = new();
16 | lexer.DefineSymbol(@"a").Kind(TestKind.A).Action(c =>
17 | {
18 | // 主动修改的 Text,不会跟着 Source.Index 发生变更。
19 | c.Text = "XXX";
20 | c.Source.Index++;
21 | Assert.AreEqual("XXX", c.Text);
22 | c.Accept();
23 | });
24 | lexer.DefineSymbol(@"b").Kind(TestKind.B).Action(c =>
25 | {
26 | // 修改 Source.Index 时,Text 会跟着发生变更。
27 | Assert.AreEqual("b", c.Text);
28 | c.Source.Index++;
29 | Assert.AreEqual("bc", c.Text);
30 | c.Accept();
31 | });
32 | var factory = lexer.GetFactory();
33 |
34 | var tokenizer = factory.CreateTokenizer();
35 | tokenizer.Load("axbcd");
36 | Assert.AreEqual(new Token(TestKind.A, "XXX", new TextSpan(0, 2)), tokenizer.Read());
37 | Assert.AreEqual(new Token(TestKind.B, "bc", new TextSpan(2, 4)), tokenizer.Read());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/UnitTestLexerRunner.cs:
--------------------------------------------------------------------------------
1 | using Cyjb.Compilers.Lexers;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 |
4 | namespace TestCompilers.Lexers;
5 |
6 | ///
7 | /// 类的单元测试。
8 | ///
9 | [TestClass]
10 | public partial class UnitTestLexerRunner
11 | {
12 | ///
13 | /// 对计算器词法分析进行测试。
14 | ///
15 | [TestMethod]
16 | public void TestDefineCalc()
17 | {
18 | LexerRunner runner = TestCalcRunnerLexer.Factory.CreateRunner();
19 | LexerRunnerContext context = new();
20 | runner.SharedContext = context;
21 |
22 | runner.Parse("1 + 20 * 3 / 4*(5+6)");
23 | Assert.AreEqual("1+20*3/4*(5+6)", context.Result);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/TestCompilers/Lexers/UnitTestTemplateDiagnostics.template.cs:
--------------------------------------------------------------------------------
1 | [LexerSymbol(10, 20, 30, 40, 50)]
2 | [LexerSymbol(Regex: "f")]
3 | [LexerSymbol("F", regex : "f")]
4 | [LexerSymbol(options: RegexOptions.None, "f")]
5 | [LexerSymbol("f", Test = 10)]
6 | [LexerSymbol("F", Kind = "f", Kind = "F2")]
7 | [LexerSymbol]
8 | [LexerSymbol(10)]
9 | [LexerSymbol("T", RegexOptions.Test)]
10 | [LexerSymbol("T", 10.3)]
11 | [LexerSymbol("T", "abc")]
12 | [LexerContext("")]
13 | [LexerSymbol("
15 | {
16 | [LexerSymbol("T")]
17 | public void InvalidAction(int a) { }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/TestCompilers/Parsers/TestCalcParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Cyjb;
3 | using Cyjb.Compilers.Parsers;
4 |
5 | namespace TestCompilers.Parsers;
6 |
7 | ///
8 | /// 用于单元测试的计算器控制器。
9 | ///
10 | [ParserLeftAssociate(Calc.Add, Calc.Sub)]
11 | [ParserLeftAssociate(Calc.Mul, Calc.Div)]
12 | [ParserRightAssociate(Calc.Pow)]
13 | [ParserNonAssociate(Calc.Id)]
14 | public partial class TestCalcParser : ParserController
15 | {
16 | [ParserProduction(Calc.E, Calc.Id)]
17 | private object? IdAction()
18 | {
19 | return this[0].Value;
20 | }
21 |
22 | [ParserProduction(Calc.E, Calc.E, Calc.Add, Calc.E)]
23 | [ParserProduction(Calc.E, Calc.E, Calc.Sub, Calc.E)]
24 | [ParserProduction(Calc.E, Calc.E, Calc.Mul, Calc.E)]
25 | [ParserProduction(Calc.E, Calc.E, Calc.Div, Calc.E)]
26 | [ParserProduction(Calc.E, Calc.E, Calc.Pow, Calc.E)]
27 | private object? BinaryAction()
28 | {
29 | double left = (double)this[0].Value!;
30 | double right = (double)this[2].Value!;
31 | return this[1].Kind switch
32 | {
33 | Calc.Add => left + right,
34 | Calc.Sub => left - right,
35 | Calc.Mul => left * right,
36 | Calc.Div => left / right,
37 | Calc.Pow => Math.Pow(left, right),
38 | _ => throw CommonExceptions.Unreachable(),
39 | };
40 | }
41 |
42 | [ParserProduction(Calc.E, Calc.LBrace, Calc.E, Calc.RBrace)]
43 | private object? BraceAction()
44 | {
45 | return this[1].Value;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/TestCompilers/Parsers/TestCalcParser.tt:
--------------------------------------------------------------------------------
1 | <#@ include file="$(PkgCyjb_Compilers_Design)\content\CompilerTemplate.t4" #>
2 |
--------------------------------------------------------------------------------
/TestCompilers/Parsers/TestProductionParser.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Linq;
3 | using Cyjb.Compilers.Parsers;
4 |
5 | namespace TestCompilers.Parsers;
6 |
7 | ///
8 | /// 用于单元测试的产生式语法分析。
9 | ///
10 | internal partial class TestProductionParser : ParserController
11 | {
12 | [ParserProduction(ProductionKind.AltExp, ProductionKind.AltExp, ProductionKind.Or, ProductionKind.Exp)]
13 | private object? OrAction()
14 | {
15 | return $"({this[0].Value})|({this[2].Value})";
16 | }
17 |
18 | [ParserProduction(ProductionKind.Exp, ProductionKind.Repeat, SymbolOptions.OneOrMore)]
19 | private object? ExpressionAction()
20 | {
21 | return string.Join(" ", ((IList)this[0].Value!).Cast