From 3cfe91e3e38f72de99adb84fa957582639ca6ba8 Mon Sep 17 00:00:00 2001 From: AntonBagliy <taccessviolation@gmail.com> Date: Thu, 21 Sep 2017 21:10:16 +0300 Subject: [PATCH] ADD: all materials for modules 1-8 --- Module3/GPLexProject/Lex1.csproj | 95 + Module3/GPLexProject/LexProjects.sln | 22 + Module3/GPLexProject/ScannerHelper.cs | 4 + Module3/GPLexProject/ShiftReduceParserCode.cs | 944 ++++++++++ Module3/GPLexProject/SimpleLex.cs | 1548 +++++++++++++++++ Module3/GPLexProject/SimpleLex.lex | 84 + Module3/GPLexProject/a.txt | 3 + Module3/GPLexProject/generateScanner.bat | 1 + Module3/GPLexProject/mymain.cs | 32 + Module5/SimpleLanguage0/Main.cs | 45 + Module5/SimpleLanguage0/ParserHelper.cs | 19 + .../Properties/AssemblyInfo.cs | 36 + .../SimpleLanguage0/ShiftReduceParserCode.cs | 944 ++++++++++ Module5/SimpleLanguage0/SimpleLang.csproj | 61 + Module5/SimpleLanguage0/SimpleLang.sln | 20 + Module5/SimpleLanguage0/SimpleLex.cs | 1485 ++++++++++++++++ Module5/SimpleLanguage0/SimpleLex.lex | 74 + Module5/SimpleLanguage0/SimpleYacc.cs | 112 ++ Module5/SimpleLanguage0/SimpleYacc.lst | 64 + Module5/SimpleLanguage0/SimpleYacc.y | 42 + Module5/SimpleLanguage0/a.txt | 10 + .../SimpleLanguage0/generateParserScanner.bat | 3 + Module6/SimpleLanguage1/Main.cs | 50 + Module6/SimpleLanguage1/ParserHelper.cs | 18 + Module6/SimpleLanguage1/ProgramTree.cs | 68 + .../Properties/AssemblyInfo.cs | 36 + .../SimpleLanguage1/ShiftReduceParserCode.cs | 944 ++++++++++ Module6/SimpleLanguage1/SimpleLang1.csproj | 62 + Module6/SimpleLanguage1/SimpleLang1.sln | 22 + Module6/SimpleLanguage1/SimpleLex.cs | 1489 ++++++++++++++++ Module6/SimpleLanguage1/SimpleLex.lex | 78 + Module6/SimpleLanguage1/SimpleYacc.cs | 166 ++ Module6/SimpleLanguage1/SimpleYacc.y | 70 + Module6/SimpleLanguage1/a.txt | 10 + .../SimpleLanguage1/generateParserScanner.bat | 3 + Module7/SimpleLanguage2/Main.cs | 56 + Module7/SimpleLanguage2/ParserHelper.cs | 33 + Module7/SimpleLanguage2/ProgramTree.cs | 145 ++ .../Properties/AssemblyInfo.cs | 36 + .../SimpleLanguage2/ShiftReduceParserCode.cs | 944 ++++++++++ Module7/SimpleLanguage2/SimpleLang2.csproj | 66 + Module7/SimpleLanguage2/SimpleLang2.sln | 22 + Module7/SimpleLanguage2/SimpleLex.cs | 1531 ++++++++++++++++ Module7/SimpleLanguage2/SimpleLex.lex | 90 + Module7/SimpleLanguage2/SimpleYacc.cs | 274 +++ Module7/SimpleLanguage2/SimpleYacc.lst | 139 ++ Module7/SimpleLanguage2/SimpleYacc.y | 119 ++ .../Visitors/AssignCountVisitor.cs | 23 + .../SimpleLanguage2/Visitors/AutoVisitor.cs | 45 + .../Visitors/PrettyPrintVisitor.cs | 88 + Module7/SimpleLanguage2/Visitors/Visitor.cs | 21 + Module7/SimpleLanguage2/a.txt | 11 + .../SimpleLanguage2/generateParserScanner.bat | 3 + Module8/SimpleLanguage3/Main.cs | 65 + Module8/SimpleLanguage3/ParserHelper.cs | 33 + Module8/SimpleLanguage3/ProgramTree.cs | 145 ++ .../Properties/AssemblyInfo.cs | 36 + .../SimpleLanguage3/ShiftReduceParserCode.cs | 944 ++++++++++ Module8/SimpleLanguage3/SimpleLang3.csproj | 68 + Module8/SimpleLanguage3/SimpleLang3.sln | 22 + Module8/SimpleLanguage3/SimpleLex.cs | 1531 ++++++++++++++++ Module8/SimpleLanguage3/SimpleLex.lex | 90 + Module8/SimpleLanguage3/SimpleYacc.cs | 274 +++ Module8/SimpleLanguage3/SimpleYacc.lst | 139 ++ Module8/SimpleLanguage3/SimpleYacc.y | 119 ++ .../Visitors/AssignCountVisitor.cs | 23 + .../SimpleLanguage3/Visitors/AutoVisitor.cs | 45 + .../GenCodeVisitors/GenCodeCreator.cs | 104 ++ .../GenCodeVisitors/GenCodeVisitor.cs | 113 ++ .../Visitors/PrettyPrintVisitor.cs | 88 + Module8/SimpleLanguage3/Visitors/Visitor.cs | 21 + Module8/SimpleLanguage3/a.txt | 11 + .../SimpleLanguage3/generateParserScanner.bat | 3 + 73 files changed, 16184 insertions(+) create mode 100644 Module3/GPLexProject/Lex1.csproj create mode 100644 Module3/GPLexProject/LexProjects.sln create mode 100644 Module3/GPLexProject/ScannerHelper.cs create mode 100644 Module3/GPLexProject/ShiftReduceParserCode.cs create mode 100644 Module3/GPLexProject/SimpleLex.cs create mode 100644 Module3/GPLexProject/SimpleLex.lex create mode 100644 Module3/GPLexProject/a.txt create mode 100644 Module3/GPLexProject/generateScanner.bat create mode 100644 Module3/GPLexProject/mymain.cs create mode 100644 Module5/SimpleLanguage0/Main.cs create mode 100644 Module5/SimpleLanguage0/ParserHelper.cs create mode 100644 Module5/SimpleLanguage0/Properties/AssemblyInfo.cs create mode 100644 Module5/SimpleLanguage0/ShiftReduceParserCode.cs create mode 100644 Module5/SimpleLanguage0/SimpleLang.csproj create mode 100644 Module5/SimpleLanguage0/SimpleLang.sln create mode 100644 Module5/SimpleLanguage0/SimpleLex.cs create mode 100644 Module5/SimpleLanguage0/SimpleLex.lex create mode 100644 Module5/SimpleLanguage0/SimpleYacc.cs create mode 100644 Module5/SimpleLanguage0/SimpleYacc.lst create mode 100644 Module5/SimpleLanguage0/SimpleYacc.y create mode 100644 Module5/SimpleLanguage0/a.txt create mode 100644 Module5/SimpleLanguage0/generateParserScanner.bat create mode 100644 Module6/SimpleLanguage1/Main.cs create mode 100644 Module6/SimpleLanguage1/ParserHelper.cs create mode 100644 Module6/SimpleLanguage1/ProgramTree.cs create mode 100644 Module6/SimpleLanguage1/Properties/AssemblyInfo.cs create mode 100644 Module6/SimpleLanguage1/ShiftReduceParserCode.cs create mode 100644 Module6/SimpleLanguage1/SimpleLang1.csproj create mode 100644 Module6/SimpleLanguage1/SimpleLang1.sln create mode 100644 Module6/SimpleLanguage1/SimpleLex.cs create mode 100644 Module6/SimpleLanguage1/SimpleLex.lex create mode 100644 Module6/SimpleLanguage1/SimpleYacc.cs create mode 100644 Module6/SimpleLanguage1/SimpleYacc.y create mode 100644 Module6/SimpleLanguage1/a.txt create mode 100644 Module6/SimpleLanguage1/generateParserScanner.bat create mode 100644 Module7/SimpleLanguage2/Main.cs create mode 100644 Module7/SimpleLanguage2/ParserHelper.cs create mode 100644 Module7/SimpleLanguage2/ProgramTree.cs create mode 100644 Module7/SimpleLanguage2/Properties/AssemblyInfo.cs create mode 100644 Module7/SimpleLanguage2/ShiftReduceParserCode.cs create mode 100644 Module7/SimpleLanguage2/SimpleLang2.csproj create mode 100644 Module7/SimpleLanguage2/SimpleLang2.sln create mode 100644 Module7/SimpleLanguage2/SimpleLex.cs create mode 100644 Module7/SimpleLanguage2/SimpleLex.lex create mode 100644 Module7/SimpleLanguage2/SimpleYacc.cs create mode 100644 Module7/SimpleLanguage2/SimpleYacc.lst create mode 100644 Module7/SimpleLanguage2/SimpleYacc.y create mode 100644 Module7/SimpleLanguage2/Visitors/AssignCountVisitor.cs create mode 100644 Module7/SimpleLanguage2/Visitors/AutoVisitor.cs create mode 100644 Module7/SimpleLanguage2/Visitors/PrettyPrintVisitor.cs create mode 100644 Module7/SimpleLanguage2/Visitors/Visitor.cs create mode 100644 Module7/SimpleLanguage2/a.txt create mode 100644 Module7/SimpleLanguage2/generateParserScanner.bat create mode 100644 Module8/SimpleLanguage3/Main.cs create mode 100644 Module8/SimpleLanguage3/ParserHelper.cs create mode 100644 Module8/SimpleLanguage3/ProgramTree.cs create mode 100644 Module8/SimpleLanguage3/Properties/AssemblyInfo.cs create mode 100644 Module8/SimpleLanguage3/ShiftReduceParserCode.cs create mode 100644 Module8/SimpleLanguage3/SimpleLang3.csproj create mode 100644 Module8/SimpleLanguage3/SimpleLang3.sln create mode 100644 Module8/SimpleLanguage3/SimpleLex.cs create mode 100644 Module8/SimpleLanguage3/SimpleLex.lex create mode 100644 Module8/SimpleLanguage3/SimpleYacc.cs create mode 100644 Module8/SimpleLanguage3/SimpleYacc.lst create mode 100644 Module8/SimpleLanguage3/SimpleYacc.y create mode 100644 Module8/SimpleLanguage3/Visitors/AssignCountVisitor.cs create mode 100644 Module8/SimpleLanguage3/Visitors/AutoVisitor.cs create mode 100644 Module8/SimpleLanguage3/Visitors/GenCodeVisitors/GenCodeCreator.cs create mode 100644 Module8/SimpleLanguage3/Visitors/GenCodeVisitors/GenCodeVisitor.cs create mode 100644 Module8/SimpleLanguage3/Visitors/PrettyPrintVisitor.cs create mode 100644 Module8/SimpleLanguage3/Visitors/Visitor.cs create mode 100644 Module8/SimpleLanguage3/a.txt create mode 100644 Module8/SimpleLanguage3/generateParserScanner.bat diff --git a/Module3/GPLexProject/Lex1.csproj b/Module3/GPLexProject/Lex1.csproj new file mode 100644 index 0000000..208f5f9 --- /dev/null +++ b/Module3/GPLexProject/Lex1.csproj @@ -0,0 +1,95 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{4DD13462-DCB4-4C3E-B777-7FEA90CEA9D1}</ProjectGuid> + <OutputType>Exe</OutputType> + <NoStandardLibraries>false</NoStandardLibraries> + <AssemblyName>sss</AssemblyName> + <RootNamespace>sss</RootNamespace> + <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent> + <FileUpgradeFlags> + </FileUpgradeFlags> + <UpgradeBackupLocation> + </UpgradeBackupLocation> + <OldToolsVersion>3.5</OldToolsVersion> + <IsWebBootstrapper>true</IsWebBootstrapper> + <TargetFrameworkVersion>v2.0</TargetFrameworkVersion> + <PublishUrl>http://localhost/sss/</PublishUrl> + <Install>true</Install> + <InstallFrom>Web</InstallFrom> + <UpdateEnabled>true</UpdateEnabled> + <UpdateMode>Foreground</UpdateMode> + <UpdateInterval>7</UpdateInterval> + <UpdateIntervalUnits>Days</UpdateIntervalUnits> + <UpdatePeriodically>false</UpdatePeriodically> + <UpdateRequired>false</UpdateRequired> + <MapFileExtensions>true</MapFileExtensions> + <ApplicationRevision>0</ApplicationRevision> + <ApplicationVersion>1.0.0.%2a</ApplicationVersion> + <UseApplicationTrust>false</UseApplicationTrust> + <BootstrapperEnabled>true</BootstrapperEnabled> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>.\bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>.\bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="ScannerHelper.cs" /> + <Compile Include="SimpleLex.cs" /> + <Compile Include="mymain.cs" /> + <Compile Include="ShiftReduceParserCode.cs" /> + </ItemGroup> + <ItemGroup> + <BootstrapperPackage Include="Microsoft.Net.Client.3.5"> + <Visible>False</Visible> + <ProductName>Клиентский профиль .NET Framework 3.5 СЃ пакетом обновления 1 %28SP1%29</ProductName> + <Install>false</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.2.0"> + <Visible>False</Visible> + <ProductName>.NET Framework 2.0 %28x86%29</ProductName> + <Install>true</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.3.0"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.0 %28x86%29</ProductName> + <Install>false</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.3.5"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5</ProductName> + <Install>false</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1</ProductName> + <Install>false</Install> + </BootstrapperPackage> + </ItemGroup> + <ItemGroup> + <None Include="SimpleLex.lex" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" /> + <ProjectExtensions> + <VisualStudio AllowExistingFolder="true" /> + </ProjectExtensions> + <PropertyGroup> + <PreBuildEvent>dir</PreBuildEvent> + </PropertyGroup> +</Project> \ No newline at end of file diff --git a/Module3/GPLexProject/LexProjects.sln b/Module3/GPLexProject/LexProjects.sln new file mode 100644 index 0000000..c1a2272 --- /dev/null +++ b/Module3/GPLexProject/LexProjects.sln @@ -0,0 +1,22 @@ +п»ї +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lex1", "Lex1.csproj", "{4DD13462-DCB4-4C3E-B777-7FEA90CEA9D1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4DD13462-DCB4-4C3E-B777-7FEA90CEA9D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DD13462-DCB4-4C3E-B777-7FEA90CEA9D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DD13462-DCB4-4C3E-B777-7FEA90CEA9D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4DD13462-DCB4-4C3E-B777-7FEA90CEA9D1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Module3/GPLexProject/ScannerHelper.cs b/Module3/GPLexProject/ScannerHelper.cs new file mode 100644 index 0000000..37f5895 --- /dev/null +++ b/Module3/GPLexProject/ScannerHelper.cs @@ -0,0 +1,4 @@ +п»їnamespace ScannerHelper +{ + public enum Tok { EOF = 0, ID, INUM, RNUM, COLON, SEMICOLON, ASSIGN, BEGIN, END, CYCLE }; +} \ No newline at end of file diff --git a/Module3/GPLexProject/ShiftReduceParserCode.cs b/Module3/GPLexProject/ShiftReduceParserCode.cs new file mode 100644 index 0000000..c110ba1 --- /dev/null +++ b/Module3/GPLexProject/ShiftReduceParserCode.cs @@ -0,0 +1,944 @@ +// Gardens Point Parser Generator +// Copyright (c) Wayne Kelly, QUT 2005-2009 +// (see accompanying GPPGcopyright.rtf) +#define EXPORT_GPPG + +using System; +using System.Text; +using System.Globalization; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; + +namespace QUT.Gppg +{ + /// <summary> + /// Abstract class for GPPG shift-reduce parsers. + /// Parsers generated by GPPG derive from this base + /// class, overriding the abstract Initialize() and + /// DoAction() methods. + /// </summary> + /// <typeparam name="TValue">Semantic value type</typeparam> + /// <typeparam name="TSpan">Location type</typeparam> +#if EXPORT_GPPG + public abstract class ShiftReduceParser<TValue, TSpan> +#else + internal abstract class ShiftReduceParser<TValue, TSpan> +#endif + where TSpan : IMerge<TSpan>, new() + { + public AbstractScanner<TValue, TSpan> scanner; + /// <summary> + /// The abstract scanner for this parser. + /// </summary> + protected AbstractScanner<TValue, TSpan> Scanner { + get { return scanner; } + set { scanner = value; } + } + + /// <summary> + /// Constructor for base class + /// </summary> + /// <param name="scanner">Scanner instance for this parser</param> + protected ShiftReduceParser(AbstractScanner<TValue, TSpan> scanner) + { + this.scanner = scanner; + } + + // ============================================================== + // TECHNICAL EXPLANATION. + // Why the next two fields are not exposed via properties. + // ============================================================== + // These fields are of the generic parameter types, and are + // frequently instantiated as struct types in derived classes. + // Semantic actions are defined in the derived classes and refer + // to instance fields of these structs. Is such cases the code + // "get_CurrentSemanticValue().myField = blah;" will fail since + // the getter pushes the value of the field, not the reference. + // So, in the presence of properties, gppg would need to encode + // such field accesses as ... + // "tmp = get_CurrentSemanticValue(); // Fetch value + // tmp.myField = blah; // update + // set_CurrentSemanticValue(tmp); " // Write update back. + // There is no issue if TValue is restricted to be a ref type. + // The same explanation applies to scanner.yylval. + // ============================================================== + /// <summary> + /// The current value of the "$$" symbolic variable in the parser + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + protected TValue CurrentSemanticValue; + + /// <summary> + /// The current value of the "@$" symbolic variable in the parser + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + protected TSpan CurrentLocationSpan; + + private TSpan LastSpan; + private int NextToken; + private State FsaState; + private bool recovering; + private int tokensSinceLastError; + + private PushdownPrefixState<State> StateStack = new PushdownPrefixState<State>(); + private PushdownPrefixState<TValue> valueStack = new PushdownPrefixState<TValue>(); + private PushdownPrefixState<TSpan> locationStack = new PushdownPrefixState<TSpan>(); + + /// <summary> + /// The stack of semantic value (YYSTYPE) values. + /// </summary> + protected PushdownPrefixState<TValue> ValueStack { get { return valueStack; } } + + /// <summary> + /// The stack of location value (YYLTYPE) varlues. + /// </summary> + protected PushdownPrefixState<TSpan> LocationStack { get { return locationStack; } } + + private int errorToken; + private int endOfFileToken; + private string[] nonTerminals; + private State[] states; + private Rule[] rules; + + /// <summary> + /// Initialization method to allow derived classes + /// to insert the rule list into this base class. + /// </summary> + /// <param name="rules">The array of Rule objects</param> + protected void InitRules(Rule[] rules) { this.rules = rules; } + + /// <summary> + /// Initialization method to allow derived classes to + /// insert the states table into this base class. + /// </summary> + /// <param name="states">The pre-initialized states table</param> + protected void InitStates(State[] states) { this.states = states; } + + /// <summary> + /// OBSOLETE FOR VERSION 1.4.0 + /// </summary> + /// <param name="size"></param> + protected void InitStateTable(int size) { states = new State[size]; } + + /// <summary> + /// Initialization method to allow derived classes + /// to insert the special value for the error and EOF tokens. + /// </summary> + /// <param name="err">The error state ordinal</param> + /// <param name="end">The EOF stat ordinal</param> + protected void InitSpecialTokens(int err, int end) + { + errorToken = err; + endOfFileToken = end; + } + + /// <summary> + /// Initialization method to allow derived classes to + /// insert the non-terminal symbol names into this base class. + /// </summary> + /// <param name="names">Non-terminal symbol names</param> + protected void InitNonTerminals(string[] names) { nonTerminals = names; } + + #region YYAbort, YYAccept etcetera. + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class AcceptException : Exception + { + internal AcceptException() { } + protected AcceptException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class AbortException : Exception + { + internal AbortException() { } + protected AbortException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class ErrorException : Exception + { + internal ErrorException() { } + protected ErrorException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + + // The following methods are only called from within + // a semantic action. The thrown exceptions can never + // propagate outside the ShiftReduceParser class in + // which they are nested. + + /// <summary> + /// Force parser to terminate, returning "true" + /// </summary> + protected static void YYAccept() { throw new AcceptException(); } + + /// <summary> + /// Force parser to terminate, returning "false" + /// </summary> + protected static void YYAbort() { throw new AbortException(); } + + /// <summary> + /// Force parser to terminate, returning + /// "false" if error recovery fails. + /// </summary> + protected static void YYError() { throw new ErrorException(); } + + /// <summary> + /// Check if parser in error recovery state. + /// </summary> + protected bool YYRecovering { get { return recovering; } } + #endregion + + /// <summary> + /// Abstract base method. ShiftReduceParser calls this + /// to initialize the base class data structures. Concrete + /// parser classes must override this method. + /// </summary> + protected abstract void Initialize(); + + /// <summary> + /// Main entry point of the Shift-Reduce Parser. + /// </summary> + /// <returns>True if parse succeeds, else false for + /// unrecoverable errors</returns> + public bool Parse() + { + Initialize(); // allow derived classes to instantiate rules, states and nonTerminals + + NextToken = 0; + FsaState = states[0]; + + StateStack.Push(FsaState); + valueStack.Push(CurrentSemanticValue); + LocationStack.Push(CurrentLocationSpan); + + while (true) + { +#if TRACE_ACTIONS + Console.Error.WriteLine("Entering state {0} ", FsaState.number); +#endif + int action = FsaState.defaultAction; + + if (FsaState.ParserTable != null) + { + if (NextToken == 0) + { +#if TRACE_ACTIONS + Console.Error.Write("Reading a token: "); +#endif + // We save the last token span, so that the location span + // of production right hand sides that begin or end with a + // nullable production will be correct. + LastSpan = scanner.yylloc; + NextToken = scanner.yylex(); + } + +#if TRACE_ACTIONS + Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken)); +#endif + if (FsaState.ParserTable.ContainsKey(NextToken)) + action = FsaState.ParserTable[NextToken]; + } + + if (action > 0) // shift + { + Shift(action); + } + else if (action < 0) // reduce + { + try + { + Reduce(-action); + if (action == -1) // accept + return true; + } + catch (Exception x) + { + if (x is AbortException) + return false; + else if (x is AcceptException) + return true; + else if (x is ErrorException && !ErrorRecovery()) + return false; + else + throw; // Rethrow x, preserving information. + + } + } + else if (action == 0) // error + if (!ErrorRecovery()) + return false; + } + } + + private void Shift(int stateIndex) + { +#if TRACE_ACTIONS + Console.Error.Write("Shifting token {0}, ", TerminalToString(NextToken)); +#endif + FsaState = states[stateIndex]; + + valueStack.Push(scanner.yylval); + StateStack.Push(FsaState); + LocationStack.Push(scanner.yylloc); + + if (recovering) + { + if (NextToken != errorToken) + tokensSinceLastError++; + + if (tokensSinceLastError > 5) + recovering = false; + } + + if (NextToken != endOfFileToken) + NextToken = 0; + } + + private void Reduce(int ruleNumber) + { +#if TRACE_ACTIONS + DisplayRule(ruleNumber); +#endif + Rule rule = rules[ruleNumber]; + // + // Default actions for unit productions. + // + if (rule.RightHandSide.Length == 1) + { + CurrentSemanticValue = valueStack.TopElement(); // Default action: $$ = $1; + CurrentLocationSpan = LocationStack.TopElement(); // Default action "@$ = @1; + } + else + { + if (rule.RightHandSide.Length == 0) + { + // Create a new blank value. + // Explicit semantic action may mutate this value + CurrentSemanticValue = default(TValue); + // The location span for an empty production will start with the + // beginning of the next lexeme, and end with the finish of the + // previous lexeme. This gives the correct behaviour when this + // nonsense value is used in later Merge operations. + CurrentLocationSpan = (scanner.yylloc != null && LastSpan != null ? + scanner.yylloc.Merge(LastSpan) : + default(TSpan)); + } + else + { + // Default action: $$ = $1; + CurrentSemanticValue = valueStack.TopElement(); + // Default action "@$ = @1.Merge(@N)" for location info. + TSpan at1 = LocationStack[LocationStack.Depth - rule.RightHandSide.Length]; + TSpan atN = LocationStack[LocationStack.Depth - 1]; + CurrentLocationSpan = + ((at1 != null && atN != null) ? at1.Merge(atN) : default(TSpan)); + } + } + + DoAction(ruleNumber); + + for (int i = 0; i < rule.RightHandSide.Length; i++) + { + StateStack.Pop(); + valueStack.Pop(); + LocationStack.Pop(); + } + +#if TRACE_ACTIONS + DisplayStack(); +#endif + FsaState = StateStack.TopElement(); + + if (FsaState.Goto.ContainsKey(rule.LeftHandSide)) + FsaState = states[FsaState.Goto[rule.LeftHandSide]]; + + StateStack.Push(FsaState); + valueStack.Push(CurrentSemanticValue); + LocationStack.Push(CurrentLocationSpan); + } + + /// <summary> + /// Execute the selected action from array. + /// Must be overriden in derived classes. + /// </summary> + /// <param name="actionNumber">Index of the action to perform</param> + protected abstract void DoAction(int actionNumber); + + private bool ErrorRecovery() + { + bool discard; + + if (!recovering) // if not recovering from previous error + ReportError(); + + if (!FindErrorRecoveryState()) + return false; + // + // The interim fix for the "looping in error recovery" + // artifact involved moving the setting of the recovering + // bool until after invalid tokens have been discarded. + // + ShiftErrorToken(); + discard = DiscardInvalidTokens(); + recovering = true; + tokensSinceLastError = 0; + return discard; + } + + private void ReportError1() + { + StringBuilder errorMsg = new StringBuilder(); + errorMsg.AppendFormat("Syntax error, unexpected {0}", TerminalToString(NextToken)); + + if (FsaState.ParserTable.Count < 7) + { + bool first = true; + foreach (int terminal in FsaState.ParserTable.Keys) + { + if (first) + errorMsg.Append(", expecting "); + else + errorMsg.Append(", or "); + + errorMsg.Append(TerminalToString(terminal)); + first = false; + } + } + scanner.yyerror(errorMsg.ToString()); + } + + private void ReportError() + { + object[] args = new object[FsaState.ParserTable.Keys.Count+1]; + args[0] = TerminalToString(NextToken); + int i=1; + foreach (int terminal in FsaState.ParserTable.Keys) + { + args[i] = TerminalToString(terminal); + i++; + } + scanner.yyerror("",args); + } + + private void ShiftErrorToken() + { + int old_next = NextToken; + NextToken = errorToken; + + Shift(FsaState.ParserTable[NextToken]); + +#if TRACE_ACTIONS + Console.Error.WriteLine("Entering state {0} ", FsaState.number); +#endif + NextToken = old_next; + } + + private bool FindErrorRecoveryState() + { + while (true) // pop states until one found that accepts error token + { + if (FsaState.ParserTable != null && + FsaState.ParserTable.ContainsKey(errorToken) && + FsaState.ParserTable[errorToken] > 0) // shift + return true; + +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: popping state {0}", StateStack.Top().number); +#endif + StateStack.Pop(); + valueStack.Pop(); + LocationStack.Pop(); + +#if TRACE_ACTIONS + DisplayStack(); +#endif + if (StateStack.IsEmpty()) + { +#if TRACE_ACTIONS + Console.Error.Write("Aborting: didn't find a state that accepts error token"); +#endif + return false; + } + else + FsaState = StateStack.TopElement(); + } + } + + private bool DiscardInvalidTokens() + { + + int action = FsaState.defaultAction; + + if (FsaState.ParserTable != null) + { + // Discard tokens until find one that works ... + while (true) + { + if (NextToken == 0) + { +#if TRACE_ACTIONS + Console.Error.Write("Reading a token: "); +#endif + NextToken = scanner.yylex(); + } + +#if TRACE_ACTIONS + Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken)); +#endif + if (NextToken == endOfFileToken) + return false; + + if (FsaState.ParserTable.ContainsKey(NextToken)) + action = FsaState.ParserTable[NextToken]; + + if (action != 0) + return true; + else + { +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: Discarding {0}", TerminalToString(NextToken)); +#endif + NextToken = 0; + } + } + } + else if (recovering && tokensSinceLastError == 0) + { + // + // Boolean recovering is not set until after the first + // error token has been shifted. Thus if we get back + // here with recovering set and no tokens read we are + // looping on the same error recovery action. This + // happens if current_state.ParserTable is null because + // the state has an LR(0) reduction, but not all + // lookahead tokens are valid. This only occurs for + // error productions that *end* on "error". + // + // This action discards tokens one at a time until + // the looping stops. Another attack would be to always + // use the LALR(1) table if a production ends on "error" + // +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: panic discard of {0}", TerminalToString(NextToken)); +#endif + if (NextToken == endOfFileToken) + return false; + NextToken = 0; + return true; + } + else + return true; + + } + + /// <summary> + /// Traditional YACC method. Discards the next input token. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyclearin")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyclearin")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + protected void yyclearin() { NextToken = 0; } + + /// <summary> + /// Tradional YACC method. Clear the "recovering" flag. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerrok")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerrok")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + protected void yyerrok() + { + recovering = false; + } + + /// <summary> + /// OBSOLETE FOR VERSION 1.4.0 + /// Method used by derived types to insert new + /// state instances in the "states" array. + /// </summary> + /// <param name="stateNumber">index of the state</param> + /// <param name="state">data for the state</param> + protected void AddState(int stateNumber, State state) + { + states[stateNumber] = state; + state.number = stateNumber; + } + + private void DisplayStack() + { + Console.Error.Write("State now"); + for (int i = 0; i < StateStack.Depth; i++) + Console.Error.Write(" {0}", StateStack[i].number); + Console.Error.WriteLine(); + } + + private void DisplayRule(int ruleNumber) + { + Console.Error.Write("Reducing stack by rule {0}, ", ruleNumber); + DisplayProduction(rules[ruleNumber]); + } + + private void DisplayProduction(Rule rule) + { + if (rule.RightHandSide.Length == 0) + Console.Error.Write("/* empty */ "); + else + foreach (int symbol in rule.RightHandSide) + Console.Error.Write("{0} ", SymbolToString(symbol)); + + Console.Error.WriteLine("-> {0}", SymbolToString(rule.LeftHandSide)); + } + + /// <summary> + /// Abstract state class naming terminal symbols. + /// This is overridden by derived classes with the + /// name (or alias) to be used in error messages. + /// </summary> + /// <param name="terminal">The terminal ordinal</param> + /// <returns></returns> + protected abstract string TerminalToString(int terminal); + + private string SymbolToString(int symbol) + { + if (symbol < 0) + return nonTerminals[-symbol]; + else + return TerminalToString(symbol); + } + + /// <summary> + /// Return text representation of argument character + /// </summary> + /// <param name="input">The character to convert</param> + /// <returns>String representation of the character</returns> + protected static string CharToString(char input) + { + switch (input) + { + case '\a': return @"'\a'"; + case '\b': return @"'\b'"; + case '\f': return @"'\f'"; + case '\n': return @"'\n'"; + case '\r': return @"'\r'"; + case '\t': return @"'\t'"; + case '\v': return @"'\v'"; + case '\0': return @"'\0'"; + default: return string.Format(CultureInfo.InvariantCulture, "'{0}'", input); + } + } + } + + /// <summary> + /// Classes implementing this interface must supply a + /// method that merges two location objects to return + /// a new object of the same type. + /// GPPG-generated parsers have the default location + /// action equivalent to "@$ = @1.Merge(@N);" where N + /// is the right-hand-side length of the production. + /// </summary> + /// <typeparam name="TSpan">The Location type</typeparam> +#if EXPORT_GPPG + public interface IMerge<TSpan> +#else + internal interface IMerge<TSpan> +#endif + { + /// <summary> + /// Interface method that creates a location object from + /// the current and last object. Typically used to create + /// a location object extending from the start of the @1 + /// object to the end of the @N object. + /// </summary> + /// <param name="last">The lexically last object to merge</param> + /// <returns>The merged location object</returns> + TSpan Merge(TSpan last); + } + + /// <summary> + /// This is the default class that carries location + /// information from the scanner to the parser. + /// If you don't declare "%YYLTYPE Foo" the parser + /// will expect to deal with this type. + /// </summary> +#if EXPORT_GPPG + public class LexLocation : IMerge<LexLocation> +#else + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + internal class LexLocation : IMerge<LexLocation> +#endif + { + private int startLine; // start line + private int startColumn; // start column + private int endLine; // end line + private int endColumn; // end column + + /// <summary> + /// The line at which the text span starts. + /// </summary> + public int StartLine { get { return startLine; } } + + /// <summary> + /// The column at which the text span starts. + /// </summary> + public int StartColumn { get { return startColumn; } } + + /// <summary> + /// The line on which the text span ends. + /// </summary> + public int EndLine { get { return endLine; } } + + /// <summary> + /// The column of the first character + /// beyond the end of the text span. + /// </summary> + public int EndColumn { get { return endColumn; } } + + /// <summary> + /// Default no-arg constructor. + /// </summary> + public LexLocation() + { } + + /// <summary> + /// Constructor for text-span with given start and end. + /// </summary> + /// <param name="sl">start line</param> + /// <param name="sc">start column</param> + /// <param name="el">end line </param> + /// <param name="ec">end column</param> + public LexLocation(int sl, int sc, int el, int ec) + { startLine = sl; startColumn = sc; endLine = el; endColumn = ec; } + + /// <summary> + /// Create a text location which spans from the + /// start of "this" to the end of the argument "last" + /// </summary> + /// <param name="last">The last location in the result span</param> + /// <returns>The merged span</returns> + public LexLocation Merge(LexLocation last) + { return new LexLocation(this.startLine, this.startColumn, last.endLine, last.endColumn); } + + } + + /// <summary> + /// Abstract scanner class that GPPG expects its scanners to + /// extend. + /// </summary> + /// <typeparam name="TValue">Semantic value type YYSTYPE</typeparam> + /// <typeparam name="TSpan">Source location type YYLTYPE</typeparam> +#if EXPORT_GPPG + public abstract class AbstractScanner<TValue, TSpan> +#else + internal abstract class AbstractScanner<TValue, TSpan> +#endif + where TSpan : IMerge<TSpan> + { + /// <summary> + /// Lexical value optionally set by the scanner. The value + /// is of the %YYSTYPE type declared in the parser spec. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylval")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylval")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + // A field must be declared for this value of parametric type, + // since it may be instantiated by a value struct. If it were + // implemented as a property, machine generated code in derived + // types would not be able to select on the returned value. + public TValue yylval; // Lexical value: set by scanner + + /// <summary> + /// Current scanner location property. The value is of the + /// type declared by %YYLTYPE in the parser specification. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylloc")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylloc")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public virtual TSpan yylloc + { + get { return default(TSpan); } // Empty implementation allowing + set { /* skip */ } // yylloc to be ignored entirely. + } + + /// <summary> + /// Main call point for LEX-like scanners. Returns an int + /// corresponding to the token recognized by the scanner. + /// </summary> + /// <returns>An int corresponding to the token</returns> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public abstract int yylex(); + + /// <summary> + /// Traditional error reporting provided by LEX-like scanners + /// to their YACC-like clients. + /// </summary> + /// <param name="format">Message format string</param> + /// <param name="args">Optional array of args</param> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerror")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerror")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public virtual void yyerror(string format, params object[] args) { } + } + + /// <summary> + /// Encapsulated state for the parser. + /// Opaque to users, visible to the tool-generated code. + /// </summary> +#if EXPORT_GPPG + public class State +#else + internal class State +#endif + { + internal int number; + internal Dictionary<int, int> ParserTable; // Terminal -> ParseAction + internal Dictionary<int, int> Goto; // NonTerminal -> State; + internal int defaultAction; // = 0; // ParseAction + + /// <summary> + /// State transition data for this state. Pairs of elements of the + /// goto array associate symbol ordinals with next state indices. + /// The actions array is passed to another constructor. + /// </summary> + /// <param name="actions">The action list</param> + /// <param name="goToList">Next state data</param> + public State(int[] actions, int[] goToList) + : this(actions) + { + Goto = new Dictionary<int, int>(); + for (int i = 0; i < goToList.Length; i += 2) + Goto.Add(goToList[i], goToList[i + 1]); + } + + /// <summary> + /// Action data for this state. Pairs of elements of the + /// action array associate action ordinals with each of + /// those symbols that have actions in the current state. + /// </summary> + /// <param name="actions">The action array</param> + public State(int[] actions) + { + ParserTable = new Dictionary<int, int>(); + for (int i = 0; i < actions.Length; i += 2) + ParserTable.Add(actions[i], actions[i + 1]); + } + + /// <summary> + /// Set the default action for this state. + /// </summary> + /// <param name="defaultAction">Ordinal of the default action</param> + public State(int defaultAction) + { + this.defaultAction = defaultAction; + } + + /// <summary> + /// Set the default action and the state transition table. + /// </summary> + /// <param name="defaultAction">The default action</param> + /// <param name="goToList">Transitions from this state</param> + public State(int defaultAction, int[] goToList) + : this(defaultAction) + { + Goto = new Dictionary<int, int>(); + for (int i = 0; i < goToList.Length; i += 2) + Goto.Add(goToList[i], goToList[i + 1]); + } + } + + /// <summary> + /// Rule representation at runtime. + /// </summary> +#if EXPORT_GPPG + public class Rule +#else + internal class Rule +#endif + { + internal int LeftHandSide; // symbol + internal int[] RightHandSide; // symbols + + /// <summary> + /// Rule constructor. This holds the ordinal of + /// the left hand side symbol, and the list of + /// right hand side symbols, in lexical order. + /// </summary> + /// <param name="left">The LHS non-terminal</param> + /// <param name="right">The RHS symbols, in lexical order</param> + public Rule(int left, int[] right) + { + this.LeftHandSide = left; + this.RightHandSide = right; + } + } + + /// <summary> + /// Stack utility for the shift-reduce parser. + /// GPPG parsers have three instances: + /// (1) The parser state stack, T = QUT.Gppg.State, + /// (2) The semantic value stack, T = TValue, + /// (3) The location stack, T = TSpan. + /// </summary> + /// <typeparam name="T"></typeparam> +#if EXPORT_GPPG + public class PushdownPrefixState<T> +#else + internal class PushdownPrefixState<T> +#endif + { + // Note that we cannot use the BCL Stack<T> class + // here as derived types need to index into stacks. + // + private T[] array = new T[8]; + private int tos = 0; + + /// <summary> + /// Indexer for values of the stack below the top. + /// </summary> + /// <param name="index">index of the element, starting from the bottom</param> + /// <returns>the selected element</returns> + public T this[int index] { get { return array[index]; } } + + /// <summary> + /// The current depth of the stack. + /// </summary> + public int Depth { get { return tos; } } + + internal void Push(T value) + { + if (tos >= array.Length) + { + T[] newarray = new T[array.Length * 2]; + System.Array.Copy(array, newarray, tos); + array = newarray; + } + array[tos++] = value; + } + + internal T Pop() + { + T rslt = array[--tos]; + array[tos] = default(T); + return rslt; + } + + internal T TopElement() { return array[tos - 1]; } + + internal bool IsEmpty() { return tos == 0; } + } +} \ No newline at end of file diff --git a/Module3/GPLexProject/SimpleLex.cs b/Module3/GPLexProject/SimpleLex.cs new file mode 100644 index 0000000..a5496f5 --- /dev/null +++ b/Module3/GPLexProject/SimpleLex.cs @@ -0,0 +1,1548 @@ +// +// This CSharp output file generated by Gardens Point LEX +// Version: 1.1.3.301 +// Machine: HUB +// DateTime: 21.09.2017 20:07:39 +// UserName: someone +// GPLEX input file <SimpleLex.lex> +// GPLEX frame file <embedded resource> +// +// Option settings: noParser, minimize +// Option settings: compressNext, persistBuffer, embedbuffers +// + +// +// Experimental embedded frame +// Version 1.1.3 of 18-April-2010 +// +// +#define BACKUP +#define STANDALONE +#define PERSIST +#define BYTEMODE + +using System; +using System.IO; +using System.Text; +using System.Globalization; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; + +using ScannerHelper; + +namespace SimpleScanner +{ + /// <summary> + /// Summary Canonical example of GPLEX automaton + /// </summary> + +#if STANDALONE + // + // These are the dummy declarations for stand-alone GPLEX applications + // normally these declarations would come from the parser. + // If you declare /noparser, or %option noparser then you get this. + // + + public enum Tokens + { + EOF = 0, maxParseToken = int.MaxValue + // must have at least these two, values are almost arbitrary + } + + public abstract class ScanBase + { + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + public abstract int yylex(); + + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yywrap")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yywrap")] + protected virtual bool yywrap() { return true; } + +#if BABEL + protected abstract int CurrentSc { get; set; } + // EolState is the 32-bit of state data persisted at + // the end of each line for Visual Studio colorization. + // The default is to return CurrentSc. You must override + // this if you want more complicated behavior. + public virtual int EolState { + get { return CurrentSc; } + set { CurrentSc = value; } + } + } + + public interface IColorScan + { + void SetSource(string source, int offset); + int GetNext(ref int state, out int start, out int end); +#endif // BABEL + } + +#endif // STANDALONE + + // If the compiler can't find the scanner base class maybe you + // need to run GPPG with the /gplex option, or GPLEX with /noparser +#if BABEL + public sealed partial class Scanner : ScanBase, IColorScan + { + private ScanBuff buffer; + int currentScOrd; // start condition ordinal + + protected override int CurrentSc + { + // The current start state is a property + // to try to avoid the user error of setting + // scState but forgetting to update the FSA + // start state "currentStart" + // + get { return currentScOrd; } // i.e. return YY_START; + set { currentScOrd = value; // i.e. BEGIN(value); + currentStart = startState[value]; } + } +#else // BABEL + public sealed partial class Scanner : ScanBase + { + private ScanBuff buffer; + int currentScOrd; // start condition ordinal +#endif // BABEL + + /// <summary> + /// The input buffer for this scanner. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public ScanBuff Buffer { get { return buffer; } } + + private static int GetMaxParseToken() { + System.Reflection.FieldInfo f = typeof(Tokens).GetField("maxParseToken"); + return (f == null ? int.MaxValue : (int)f.GetValue(null)); + } + + static int parserMax = GetMaxParseToken(); + + enum Result {accept, noMatch, contextFound}; + + const int maxAccept = 20; + const int initial = 21; + const int eofNum = 0; + const int goStart = -1; + const int INITIAL = 0; + +#region user code +public int LexValueInt; + public double LexValueDouble; +#endregion user code + + int state; + int currentStart = startState[0]; + int code; // last code read + int cCol; // column number of code + int lNum; // current line number + // + // The following instance variables are used, among other + // things, for constructing the yylloc location objects. + // + int tokPos; // buffer position at start of token + int tokCol; // zero-based column number at start of token + int tokLin; // line number at start of token + int tokEPos; // buffer position at end of token + int tokECol; // column number at end of token + int tokELin; // line number at end of token + string tokTxt; // lazily constructed text of token +#if STACK + private Stack<int> scStack = new Stack<int>(); +#endif // STACK + +#region ScannerTables + struct Table { + public int min; public int rng; public int dflt; + public sbyte[] nxt; + public Table(int m, int x, int d, sbyte[] n) { + min = m; rng = x; dflt = d; nxt = n; + } + }; + + static int[] startState = new int[] {21, 0}; + + static Table[] NxS = new Table[23] { +/* NxS[ 0] */ new Table(0, 0, 0, null), +/* NxS[ 1] */ new Table(0, 0, -1, null), +/* NxS[ 2] */ new Table(46, 12, -1, new sbyte[] {22, -1, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2}), +/* NxS[ 3] */ new Table(61, 1, -1, new sbyte[] {19}), +/* NxS[ 4] */ new Table(0, 0, -1, null), +/* NxS[ 5] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 6] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 15, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 7] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 11, 5}), +/* NxS[ 8] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 9, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 9] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 10, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 10] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 11] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 12, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 12] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 13, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 13] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 14] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 15] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 5, + 5, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 16] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 17] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 18, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 18] */ new Table(48, 75, -1, new sbyte[] {5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, -1, -1, -1, -1, 5, -1, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5}), +/* NxS[ 19] */ new Table(0, 0, -1, null), +/* NxS[ 20] */ new Table(48, 10, -1, new sbyte[] {20, 20, 20, 20, 20, 20, + 20, 20, 20, 20}), +/* NxS[ 21] */ new Table(10, 113, 1, new sbyte[] {-1, 1, 1, -1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 1, 1, 1, 1, + 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 5, + 1, 5, 6, 7, 5, 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}), +/* NxS[ 22] */ new Table(48, 10, -1, new sbyte[] {20, 20, 20, 20, 20, 20, + 20, 20, 20, 20}), + }; + +int NextState() { + if (code == ScanBuff.EndOfFile) + return eofNum; + else + unchecked { + int rslt; + int idx = (byte)(code - NxS[state].min); + if ((uint)idx >= (uint)NxS[state].rng) rslt = NxS[state].dflt; + else rslt = NxS[state].nxt[idx]; + return rslt; + } +} + +#endregion + + +#if BACKUP + // ============================================================== + // == Nested struct used for backup in automata that do backup == + // ============================================================== + + struct Context // class used for automaton backup. + { + public int bPos; + public int rPos; // scanner.readPos saved value + public int cCol; + public int lNum; // Need this in case of backup over EOL. + public int state; + public int cChr; + } + + private Context ctx = new Context(); +#endif // BACKUP + + // ============================================================== + // ==== Nested struct to support input switching in scanners ==== + // ============================================================== + + struct BufferContext { + internal ScanBuff buffSv; + internal int chrSv; + internal int cColSv; + internal int lNumSv; + } + + // ============================================================== + // ===== Private methods to save and restore buffer contexts ==== + // ============================================================== + + /// <summary> + /// This method creates a buffer context record from + /// the current buffer object, together with some + /// scanner state values. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + BufferContext MkBuffCtx() + { + BufferContext rslt; + rslt.buffSv = this.buffer; + rslt.chrSv = this.code; + rslt.cColSv = this.cCol; + rslt.lNumSv = this.lNum; + return rslt; + } + + /// <summary> + /// This method restores the buffer value and allied + /// scanner state from the given context record value. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void RestoreBuffCtx(BufferContext value) + { + this.buffer = value.buffSv; + this.code = value.chrSv; + this.cCol = value.cColSv; + this.lNum = value.lNumSv; + } + // =================== End Nested classes ======================= + +#if !NOFILES + public Scanner(Stream file) { + SetSource(file); // no unicode option + } + +#endif // !NOFILES + + public Scanner() { } + + private int readPos; + + void GetCode() + { + if (code == '\n') // This needs to be fixed for other conventions + // i.e. [\r\n\205\u2028\u2029] + { + cCol = -1; + lNum++; + } + readPos = buffer.Pos; + + // Now read new codepoint. + code = buffer.Read(); + if (code > ScanBuff.EndOfFile) + { +#if (!BYTEMODE) + if (code >= 0xD800 && code <= 0xDBFF) + { + int next = buffer.Read(); + if (next < 0xDC00 || next > 0xDFFF) + code = ScanBuff.UnicodeReplacementChar; + else + code = (0x10000 + (code & 0x3FF << 10) + (next & 0x3FF)); + } +#endif + cCol++; + } + } + + void MarkToken() + { +#if (!PERSIST) + buffer.Mark(); +#endif + tokPos = readPos; + tokLin = lNum; + tokCol = cCol; + } + + void MarkEnd() + { + tokTxt = null; + tokEPos = readPos; + tokELin = lNum; + tokECol = cCol; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int Peek() + { + int rslt, codeSv = code, cColSv = cCol, lNumSv = lNum, bPosSv = buffer.Pos; + GetCode(); rslt = code; + lNum = lNumSv; cCol = cColSv; code = codeSv; buffer.Pos = bPosSv; + return rslt; + } + + // ============================================================== + // ===== Initialization of string-based input buffers ==== + // ============================================================== + + /// <summary> + /// Create and initialize a StringBuff buffer object for this scanner + /// </summary> + /// <param name="source">the input string</param> + /// <param name="offset">starting offset in the string</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(string source, int offset) + { + this.buffer = ScanBuff.GetBuffer(source); + this.buffer.Pos = offset; + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } + +#if !NOFILES + // ================ LineBuffer Initialization =================== + + /// <summary> + /// Create and initialize a LineBuff buffer object for this scanner + /// </summary> + /// <param name="source">the list of input strings</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(IList<string> source) + { + this.buffer = ScanBuff.GetBuffer(source); + this.code = '\n'; // to initialize yyline, yycol and lineStart + this.lNum = 0; + GetCode(); + } + + // =============== StreamBuffer Initialization ================== + + /// <summary> + /// Create and initialize a StreamBuff buffer object for this scanner. + /// StreamBuff is buffer for 8-bit byte files. + /// </summary> + /// <param name="source">the input byte stream</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(Stream source) + { + this.buffer = ScanBuff.GetBuffer(source); + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } + +#if !BYTEMODE + // ================ TextBuffer Initialization =================== + + /// <summary> + /// Create and initialize a TextBuff buffer object for this scanner. + /// TextBuff is a buffer for encoded unicode files. + /// </summary> + /// <param name="source">the input text file</param> + /// <param name="fallbackCodePage">Code page to use if file has + /// no BOM. For 0, use machine default; for -1, 8-bit binary</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(Stream source, int fallbackCodePage) + { + this.buffer = ScanBuff.GetBuffer(source, fallbackCodePage); + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } +#endif // !BYTEMODE +#endif // !NOFILES + + // ============================================================== + +#if BABEL + // + // Get the next token for Visual Studio + // + // "state" is the inout mode variable that maintains scanner + // state between calls, using the EolState property. In principle, + // if the calls of EolState are costly set could be called once + // only per line, at the start; and get called only at the end + // of the line. This needs more infrastructure ... + // + public int GetNext(ref int state, out int start, out int end) + { + Tokens next; + int s, e; + s = state; // state at start + EolState = state; + next = (Tokens)Scan(); + state = EolState; + e = state; // state at end; + start = tokPos; + end = tokEPos - 1; // end is the index of last char. + return (int)next; + } +#endif // BABEL + + // ======== AbstractScanner<> Implementation ========= + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + public override int yylex() + { + // parserMax is set by reflecting on the Tokens + // enumeration. If maxParseToken is defined + // that is used, otherwise int.MaxValue is used. + int next; + do { next = Scan(); } while (next >= parserMax); + return next; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yypos { get { return tokPos; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yyline { get { return tokLin; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yycol { get { return tokCol; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yytext")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yytext")] + public string yytext + { + get + { + if (tokTxt == null) + tokTxt = buffer.GetString(tokPos, tokEPos); + return tokTxt; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void yyless(int n) + { + buffer.Pos = tokPos; + // Must read at least one char, so set before start. + cCol = tokCol - 1; + GetCode(); + // Now ensure that line counting is correct. + lNum = tokLin; + // And count the rest of the text. + for (int i = 0; i < n; i++) GetCode(); + MarkEnd(); + } + + // + // It would be nice to count backward in the text + // but it does not seem possible to re-establish + // the correct column counts except by going forward. + // + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void _yytrunc(int n) { yyless(yyleng - n); } + + // + // This is painful, but we no longer count + // codepoints. For the overwhelming majority + // of cases the single line code is fast, for + // the others, well, at least it is all in the + // buffer so no files are touched. Note that we + // can't use (tokEPos - tokPos) because of the + // possibility of surrogate pairs in the token. + // + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyleng")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyleng")] + public int yyleng + { + get { +#if BYTEMODE + return tokEPos - tokPos; +#else + if (tokELin == tokLin) + return tokECol - tokCol; + else { + int ch; + int count = 0; + int save = buffer.Pos; + buffer.Pos = tokPos; + do { + ch = buffer.Read(); + if (!char.IsHighSurrogate((char)ch)) count++; + } while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile); + buffer.Pos = save; + return count; + } +#endif // BYTEMODE + } + } + + // ============ methods available in actions ============== + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal int YY_START { + get { return currentScOrd; } + set { currentScOrd = value; + currentStart = startState[value]; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void BEGIN(int next) { + currentScOrd = next; + currentStart = startState[next]; + } + + // ============== The main tokenizer code ================= + + int Scan() + { + for (; ; ) + { + int next; // next state to enter +#if BACKUP + Result rslt = Result.noMatch; +#endif // BACKUP +#if LEFTANCHORS + for (;;) + { + // Discard characters that do not start any pattern. + // Must check the left anchor condition after *every* GetCode! + state = ((cCol == 0) ? anchorState[currentScOrd] : currentStart); + if ((next = NextState()) != goStart) + break; // LOOP EXIT HERE... + GetCode(); + } + +#else // !LEFTANCHORS + state = currentStart; + while ((next = NextState()) == goStart) + // At this point, the current character has no + // transition from the current state. We discard + // the "no-match" char. In traditional LEX such + // characters are echoed to the console. + GetCode(); +#endif // LEFTANCHORS + // At last, a valid transition ... + MarkToken(); + state = next; + GetCode(); + + while ((next = NextState()) > eofNum) // Exit for goStart AND for eofNum +#if BACKUP + if (state <= maxAccept && next > maxAccept) // need to prepare backup data + { + // ctx is an object. The fields may be + // mutated by the call to Recurse2. + // On return the data in ctx is the + // *latest* accept state that was found. + + rslt = Recurse2(ref ctx, next); + if (rslt == Result.noMatch) + RestoreStateAndPos(ref ctx); + break; + } + else +#endif // BACKUP + { + state = next; + GetCode(); + } + if (state <= maxAccept) + { + MarkEnd(); +#region ActionSwitch +#pragma warning disable 162 + switch (state) + { + case eofNum: + if (yywrap()) + return (int)Tokens.EOF; + break; + case 1: +LexError(); + return 0; + break; + case 2: +LexValueInt = int.Parse(yytext); + return (int)Tok.INUM; + break; + case 3: +return (int)Tok.COLON; + break; + case 4: +return (int)Tok.SEMICOLON; + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 11: + case 12: + case 13: + case 15: + case 16: + case 17: +return (int)Tok.ID; + break; + case 10: +return (int)Tok.END; + break; + case 14: +return (int)Tok.CYCLE; + break; + case 18: +return (int)Tok.BEGIN; + break; + case 19: +return (int)Tok.ASSIGN; + break; + case 20: +LexValueDouble = double.Parse(yytext); + return (int)Tok.RNUM; + break; + default: + break; + } +#pragma warning restore 162 +#endregion + } + } + } + +#if BACKUP + Result Recurse2(ref Context ctx, int next) + { + // Assert: at entry "state" is an accept state AND + // NextState(state, code) != goStart AND + // NextState(state, code) is not an accept state. + // + SaveStateAndPos(ref ctx); + state = next; + GetCode(); + + while ((next = NextState()) > eofNum) + { + if (state <= maxAccept && next > maxAccept) // need to update backup data + SaveStateAndPos(ref ctx); + state = next; + if (state == eofNum) return Result.accept; + GetCode(); + } + return (state <= maxAccept ? Result.accept : Result.noMatch); + } + + void SaveStateAndPos(ref Context ctx) + { + ctx.bPos = buffer.Pos; + ctx.rPos = readPos; + ctx.cCol = cCol; + ctx.lNum = lNum; + ctx.state = state; + ctx.cChr = code; + } + + void RestoreStateAndPos(ref Context ctx) + { + buffer.Pos = ctx.bPos; + readPos = ctx.rPos; + cCol = ctx.cCol; + lNum = ctx.lNum; + state = ctx.state; + code = ctx.cChr; + } + +#endif // BACKUP + + // ============= End of the tokenizer code ================ + +#if STACK + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void yy_clear_stack() { scStack.Clear(); } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal int yy_top_state() { return scStack.Peek(); } + + internal void yy_push_state(int state) + { + scStack.Push(currentScOrd); + BEGIN(state); + } + + internal void yy_pop_state() + { + // Protect against input errors that pop too far ... + if (scStack.Count > 0) { + int newSc = scStack.Pop(); + BEGIN(newSc); + } // Otherwise leave stack unchanged. + } + #endif // STACK + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void ECHO() { Console.Out.Write(yytext); } + +#region UserCodeSection + +public void LexError() +{ + Console.WriteLine("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); +} + +public string TokToString(Tok tok) +{ + switch (tok) + { + case Tok.ID: + return tok + " " + yytext; + case Tok.INUM: + return tok + " " + LexValueInt; + case Tok.RNUM: + return tok + " " + LexValueDouble; + default: + return tok + ""; + } +} + +#endregion + } // end class $Scanner + +// ============================================================== +// <auto-generated> +// This code automatically produced from an embedded resource. +// Do not edit this file, or it will become incompatible with +// the specification from which it was generated. +// </auto-generated> +// ============================================================== + +// Code copied from GPLEX embedded resource + [Serializable] + public class BufferException : Exception + { + public BufferException() { } + public BufferException(string message) : base(message) { } + public BufferException(string message, Exception innerException) + : base(message, innerException) { } + protected BufferException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + } + + public abstract class ScanBuff + { + private string fileNm; + + public const int EndOfFile = -1; + public const int UnicodeReplacementChar = 0xFFFD; + + public bool IsFile { get { return (fileNm != null); } } + public string FileName { get { return fileNm; } set { fileNm = value; } } + + public abstract int Pos { get; set; } + public abstract int Read(); + public virtual void Mark() { } + + public abstract string GetString(int begin, int limit); + + public static ScanBuff GetBuffer(string source) + { + return new StringBuffer(source); + } + + public static ScanBuff GetBuffer(IList<string> source) + { + return new LineBuffer(source); + } + + public static ScanBuff GetBuffer(Stream source) + { + return new BuildBuffer(source); + } + +#if (!BYTEMODE) + public static ScanBuff GetBuffer(Stream source, int fallbackCodePage) + { + return new BuildBuffer(source, fallbackCodePage); + } +#endif + } + + #region Buffer classes + + // ============================================================== + // ===== Definitions for various ScanBuff derived classes ==== + // ============================================================== + // =============== String input ================ + // ============================================================== + + /// <summary> + /// This class reads characters from a single string as + /// required, for example, by Visual Studio language services + /// </summary> + sealed class StringBuffer : ScanBuff + { + string str; // input buffer + int bPos; // current position in buffer + int sLen; + + public StringBuffer(string source) + { + this.str = source; + this.sLen = source.Length; + this.FileName = null; + } + + public override int Read() + { + if (bPos < sLen) return str[bPos++]; + else if (bPos == sLen) { bPos++; return '\n'; } // one strike, see new line + else { bPos++; return EndOfFile; } // two strikes and you're out! + } + + public override string GetString(int begin, int limit) + { + // "limit" can be greater than sLen with the BABEL + // option set. Read returns a "virtual" EOL if + // an attempt is made to read past the end of the + // string buffer. Without the guard any attempt + // to fetch yytext for a token that includes the + // EOL will throw an index exception. + if (limit > sLen) limit = sLen; + if (limit <= begin) return ""; + else return str.Substring(begin, limit - begin); + } + + public override int Pos + { + get { return bPos; } + set { bPos = value; } + } + + public override string ToString() { return "StringBuffer"; } + } + + // ============================================================== + // The LineBuff class contributed by Nigel Horspool, + // nigelh@cs.uvic.cs + // ============================================================== + + sealed class LineBuffer : ScanBuff + { + IList<string> line; // list of source lines from a file + int numLines; // number of strings in line list + string curLine; // current line in that list + int cLine; // index of current line in the list + int curLen; // length of current line + int curLineStart; // position of line start in whole file + int curLineEnd; // position of line end in whole file + int maxPos; // max position ever visited in whole file + int cPos; // ordinal number of code in source + + // Constructed from a list of strings, one per source line. + // The lines have had trailing '\n' characters removed. + public LineBuffer(IList<string> lineList) + { + line = lineList; + numLines = line.Count; + cPos = curLineStart = 0; + curLine = (numLines > 0 ? line[0] : ""); + maxPos = curLineEnd = curLen = curLine.Length; + cLine = 1; + FileName = null; + } + + public override int Read() + { + if (cPos < curLineEnd) + return curLine[cPos++ - curLineStart]; + if (cPos++ == curLineEnd) + return '\n'; + if (cLine >= numLines) + return EndOfFile; + curLine = line[cLine]; + curLen = curLine.Length; + curLineStart = curLineEnd + 1; + curLineEnd = curLineStart + curLen; + if (curLineEnd > maxPos) + maxPos = curLineEnd; + cLine++; + return curLen > 0 ? curLine[0] : '\n'; + } + + // To speed up searches for the line containing a position + private int cachedPosition; + private int cachedIxdex; + private int cachedLineStart; + + // Given a position pos within the entire source, the results are + // ix -- the index of the containing line + // lstart -- the position of the first character on that line + private void findIndex(int pos, out int ix, out int lstart) + { + if (pos >= cachedPosition) + { + ix = cachedIxdex; lstart = cachedLineStart; + } + else + { + ix = lstart = 0; + } + for (; ; ) + { + int len = line[ix].Length + 1; + if (pos < lstart + len) break; + lstart += len; + ix++; + } + cachedPosition = pos; + cachedIxdex = ix; + cachedLineStart = lstart; + } + + public override string GetString(int begin, int limit) + { + if (begin >= maxPos || limit <= begin) return ""; + int endIx, begIx, endLineStart, begLineStart; + findIndex(begin, out begIx, out begLineStart); + int begCol = begin - begLineStart; + findIndex(limit, out endIx, out endLineStart); + int endCol = limit - endLineStart; + string s = line[begIx]; + if (begIx == endIx) + { + // the usual case, substring all on one line + return (endCol <= s.Length) ? + s.Substring(begCol, endCol - begCol) + : s.Substring(begCol) + "\n"; + } + // the string spans multiple lines, yuk! + StringBuilder sb = new StringBuilder(); + if (begCol < s.Length) + sb.Append(s.Substring(begCol)); + for (; ; ) + { + sb.Append("\n"); + s = line[++begIx]; + if (begIx >= endIx) break; + sb.Append(s); + } + if (endCol <= s.Length) + { + sb.Append(s.Substring(0, endCol)); + } + else + { + sb.Append(s); + sb.Append("\n"); + } + return sb.ToString(); + } + + public override int Pos + { + get { return cPos; } + set + { + cPos = value; + findIndex(cPos, out cLine, out curLineStart); + curLine = line[cLine]; + curLineEnd = curLineStart + curLine.Length; + } + } + + public override string ToString() { return "LineBuffer"; } + } + + + // ============================================================== + // ===== class BuildBuff : for unicode text files ======== + // ============================================================== + + class BuildBuffer : ScanBuff + { + // Double buffer for char stream. + class BufferElement + { + StringBuilder bldr = new StringBuilder(); + StringBuilder next = new StringBuilder(); + int minIx; + int maxIx; + int brkIx; + bool appendToNext; + + internal BufferElement() { } + + internal int MaxIndex { get { return maxIx; } } + // internal int MinIndex { get { return minIx; } } + + internal char this[int index] + { + get + { + if (index < minIx || index >= maxIx) + throw new BufferException("Index was outside data buffer"); + else if (index < brkIx) + return bldr[index - minIx]; + else + return next[index - brkIx]; + } + } + + internal void Append(char[] block, int count) + { + maxIx += count; + if (appendToNext) + this.next.Append(block, 0, count); + else + { + this.bldr.Append(block, 0, count); + brkIx = maxIx; + appendToNext = true; + } + } + + internal string GetString(int start, int limit) + { + if (limit <= start) + return ""; + if (start >= minIx && limit <= maxIx) + if (limit < brkIx) // String entirely in bldr builder + return bldr.ToString(start - minIx, limit - start); + else if (start >= brkIx) // String entirely in next builder + return next.ToString(start - brkIx, limit - start); + else // Must do a string-concatenation + return + bldr.ToString(start - minIx, brkIx - start) + + next.ToString(0, limit - brkIx); + else + throw new BufferException("String was outside data buffer"); + } + + internal void Mark(int limit) + { + if (limit > brkIx + 16) // Rotate blocks + { + StringBuilder temp = bldr; + bldr = next; + next = temp; + next.Length = 0; + minIx = brkIx; + brkIx = maxIx; + } + } + } + + BufferElement data = new BufferElement(); + + int bPos; // Postion index in the StringBuilder + BlockReader NextBlk; // Delegate that serves char-arrays; + + private string EncodingName + { + get + { + StreamReader rdr = NextBlk.Target as StreamReader; + return (rdr == null ? "raw-bytes" : rdr.CurrentEncoding.BodyName); + } + } + + public BuildBuffer(Stream stream) + { + FileStream fStrm = (stream as FileStream); + if (fStrm != null) FileName = fStrm.Name; + NextBlk = BlockReaderFactory.Raw(stream); + } + +#if (!BYTEMODE) + public BuildBuffer(Stream stream, int fallbackCodePage) + { + FileStream fStrm = (stream as FileStream); + if (fStrm != null) FileName = fStrm.Name; + NextBlk = BlockReaderFactory.Get(stream, fallbackCodePage); + } +#endif + + /// <summary> + /// Marks a conservative lower bound for the buffer, + /// allowing space to be reclaimed. If an application + /// needs to call GetString at arbitrary past locations + /// in the input stream, Mark() is not called. + /// </summary> + public override void Mark() { data.Mark(bPos - 2); } + + public override int Pos + { + get { return bPos; } + set { bPos = value; } + } + + + /// <summary> + /// Read returns the ordinal number of the next char, or + /// EOF (-1) for an end of stream. Note that the next + /// code point may require *two* calls of Read(). + /// </summary> + /// <returns></returns> + public override int Read() + { + // + // Characters at positions + // [data.offset, data.offset + data.bldr.Length) + // are available in data.bldr. + // + if (bPos < data.MaxIndex) + { + // ch0 cannot be EOF + return (int)data[bPos++]; + } + else // Read from underlying stream + { + // Experimental code, blocks of page size + char[] chrs = new char[4096]; + int count = NextBlk(chrs, 0, 4096); + if (count == 0) + return EndOfFile; + else + { + data.Append(chrs, count); + return (int)data[bPos++]; + } + } + } + + public override string GetString(int begin, int limit) + { + return data.GetString(begin, limit); + } + + public override string ToString() + { + return "StringBuilder buffer, encoding: " + this.EncodingName; + } + } + + // =============== End ScanBuff-derived classes ================== + + public delegate int BlockReader(char[] block, int index, int number); + + // A delegate factory, serving up a delegate that + // reads a block of characters from the underlying + // encoded stream, via a StreamReader object. + // + public static class BlockReaderFactory + { + public static BlockReader Raw(Stream stream) + { + return delegate(char[] block, int index, int number) + { + byte[] b = new byte[number]; + int count = stream.Read(b, 0, number); + int i = 0; + int j = index; + for (; i < count; i++, j++) + block[j] = (char)b[i]; + return count; + }; + } + +#if (!BYTEMODE) + public static BlockReader Get(Stream stream, int fallbackCodePage) + { + Encoding encoding; + int preamble = Preamble(stream); + + if (preamble != 0) // There is a valid BOM here! + encoding = Encoding.GetEncoding(preamble); + else if (fallbackCodePage == -1) // Fallback is "raw" bytes + return Raw(stream); + else if (fallbackCodePage != -2) // Anything but "guess" + encoding = Encoding.GetEncoding(fallbackCodePage); + else // This is the "guess" option + { + int guess = new Guesser(stream).GuessCodePage(); + stream.Seek(0, SeekOrigin.Begin); + if (guess == -1) // ==> this is a 7-bit file + encoding = Encoding.ASCII; + else if (guess == 65001) + encoding = Encoding.UTF8; + else // ==> use the machine default + encoding = Encoding.Default; + } + StreamReader reader = new StreamReader(stream, encoding); + return reader.Read; + } + + static int Preamble(Stream stream) + { + int b0 = stream.ReadByte(); + int b1 = stream.ReadByte(); + + if (b0 == 0xfe && b1 == 0xff) + return 1201; // UTF16BE + if (b0 == 0xff && b1 == 0xfe) + return 1200; // UTF16LE + + int b2 = stream.ReadByte(); + if (b0 == 0xef && b1 == 0xbb && b2 == 0xbf) + return 65001; // UTF8 + // + // There is no unicode preamble, so we + // return denoter for the machine default. + // + stream.Seek(0, SeekOrigin.Begin); + return 0; + } +#endif // !BYTEMODE + } + #endregion Buffer classes + + // ============================================================== + // ============ class CodePageHandling ============= + // ============================================================== + + public static class CodePageHandling + { + public static int GetCodePage(string option) + { + string command = option.ToUpperInvariant(); + if (command.StartsWith("CodePage:", StringComparison.OrdinalIgnoreCase)) + command = command.Substring(9); + try + { + if (command.Equals("RAW")) + return -1; + else if (command.Equals("GUESS")) + return -2; + else if (command.Equals("DEFAULT")) + return 0; + else if (char.IsDigit(command[0])) + return int.Parse(command, CultureInfo.InvariantCulture); + else + { + Encoding enc = Encoding.GetEncoding(command); + return enc.CodePage; + } + } + catch (FormatException) + { + Console.Error.WriteLine( + "Invalid format \"{0}\", using machine default", option); + } + catch (ArgumentException) + { + Console.Error.WriteLine( + "Unknown code page \"{0}\", using machine default", option); + } + return 0; + } + } +#region guesser +#if (!BYTEMODE) + // ============================================================== + // ============ Encoding Guesser ============= + // ============================================================== + + /// <summary> + /// This class provides a simple finite state automaton that + /// scans the file looking for (1) valid UTF-8 byte patterns, + /// (2) bytes >= 0x80 which are not part of a UTF-8 sequence. + /// The method then guesses whether it is UTF-8 or maybe some + /// local machine default encoding. This works well for the + /// various Latin encodings. + /// </summary> + internal class Guesser + { + ScanBuff buffer; + + public int GuessCodePage() { return Scan(); } + + const int maxAccept = 10; + const int initial = 0; + const int eofNum = 0; + const int goStart = -1; + const int INITIAL = 0; + const int EndToken = 0; + + #region user code + /* + * Reads the bytes of a file to determine if it is + * UTF-8 or a single-byte code page file. + */ + public long utfX; + public long uppr; + #endregion user code + + int state; + int currentStart = startState[0]; + int code; + + #region ScannerTables + static int[] startState = new int[] { 11, 0 }; + + #region CharacterMap + static sbyte[] map = new sbyte[256] { +/* '\0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x10' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x20' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '@' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 'P' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '`' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 'p' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x80' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\x90' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xA0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xB0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xC0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* '\xD0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* '\xE0' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* '\xF0' */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5 }; + #endregion + + static sbyte[][] nextState = new sbyte[][] { + new sbyte[] {0, 0, 0, 0, 0, 0}, + new sbyte[] {-1, -1, 10, -1, -1, -1}, + new sbyte[] {-1, -1, -1, -1, -1, -1}, + new sbyte[] {-1, -1, 8, -1, -1, -1}, + new sbyte[] {-1, -1, 5, -1, -1, -1}, + new sbyte[] {-1, -1, 6, -1, -1, -1}, + new sbyte[] {-1, -1, 7, -1, -1, -1}, + null, + new sbyte[] {-1, -1, 9, -1, -1, -1}, + null, + null, + new sbyte[] {-1, 1, 2, 3, 4, 2} + }; + + + [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + // Reason for suppression: cannot have self-reference in array initializer. + static Guesser() + { + nextState[7] = nextState[2]; + nextState[9] = nextState[2]; + nextState[10] = nextState[2]; + } + + int NextState() + { + if (code == ScanBuff.EndOfFile) + return eofNum; + else + return nextState[state][map[code]]; + } + #endregion + + public Guesser(System.IO.Stream file) { SetSource(file); } + + public void SetSource(System.IO.Stream source) + { + this.buffer = new BuildBuffer(source); + code = buffer.Read(); + } + + int Scan() + { + for (; ; ) + { + int next; + state = currentStart; + while ((next = NextState()) == goStart) + code = buffer.Read(); + + state = next; + code = buffer.Read(); + + while ((next = NextState()) > eofNum) + { + state = next; + code = buffer.Read(); + } + if (state <= maxAccept) + { + #region ActionSwitch +#pragma warning disable 162 + switch (state) + { + case eofNum: + switch (currentStart) + { + case 11: + if (utfX == 0 && uppr == 0) return -1; /* raw ascii */ + else if (uppr * 10 > utfX) return 0; /* default code page */ + else return 65001; /* UTF-8 encoding */ + break; + } + return EndToken; + case 1: // Recognized '{Upper128}', Shortest string "\xC0" + case 2: // Recognized '{Upper128}', Shortest string "\x80" + case 3: // Recognized '{Upper128}', Shortest string "\xE0" + case 4: // Recognized '{Upper128}', Shortest string "\xF0" + uppr++; + break; + case 5: // Recognized '{Utf8pfx4}{Utf8cont}', Shortest string "\xF0\x80" + uppr += 2; + break; + case 6: // Recognized '{Utf8pfx4}{Utf8cont}{2}', Shortest string "\xF0\x80\x80" + uppr += 3; + break; + case 7: // Recognized '{Utf8pfx4}{Utf8cont}{3}', Shortest string "\xF0\x80\x80\x80" + utfX += 3; + break; + case 8: // Recognized '{Utf8pfx3}{Utf8cont}', Shortest string "\xE0\x80" + uppr += 2; + break; + case 9: // Recognized '{Utf8pfx3}{Utf8cont}{2}', Shortest string "\xE0\x80\x80" + utfX += 2; + break; + case 10: // Recognized '{Utf8pfx2}{Utf8cont}', Shortest string "\xC0\x80" + utfX++; + break; + default: + break; + } +#pragma warning restore 162 + #endregion + } + } + } + } // end class Guesser + +#endif // !BYTEMODE +#endregion + +// End of code copied from embedded resource + +} // end namespace diff --git a/Module3/GPLexProject/SimpleLex.lex b/Module3/GPLexProject/SimpleLex.lex new file mode 100644 index 0000000..c0434f0 --- /dev/null +++ b/Module3/GPLexProject/SimpleLex.lex @@ -0,0 +1,84 @@ +%using ScannerHelper; +%namespace SimpleScanner + +Alpha [a-zA-Z_] +Digit [0-9] +AlphaDigit {Alpha}|{Digit} +INTNUM {Digit}+ +REALNUM {INTNUM}\.{INTNUM} +ID {Alpha}{AlphaDigit}* + +// Здесь можно делать описания типов, переменных и методов - они попадают в класс Scanner +%{ + public int LexValueInt; + public double LexValueDouble; +%} + +%% +{INTNUM} { + LexValueInt = int.Parse(yytext); + return (int)Tok.INUM; +} + +{REALNUM} { + LexValueDouble = double.Parse(yytext); + return (int)Tok.RNUM; +} + +begin { + return (int)Tok.BEGIN; +} + +end { + return (int)Tok.END; +} + +cycle { + return (int)Tok.CYCLE; +} + +{ID} { + return (int)Tok.ID; +} + +":" { + return (int)Tok.COLON; +} + +":=" { + return (int)Tok.ASSIGN; +} + +";" { + return (int)Tok.SEMICOLON; +} + +[^ \r\n] { + LexError(); + return 0; // конец разбора +} + +%% + +// Здесь можно делать описания переменных и методов - они тоже попадают в класс Scanner + +public void LexError() +{ + Console.WriteLine("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); +} + +public string TokToString(Tok tok) +{ + switch (tok) + { + case Tok.ID: + return tok + " " + yytext; + case Tok.INUM: + return tok + " " + LexValueInt; + case Tok.RNUM: + return tok + " " + LexValueDouble; + default: + return tok + ""; + } +} + diff --git a/Module3/GPLexProject/a.txt b/Module3/GPLexProject/a.txt new file mode 100644 index 0000000..cda6431 --- /dev/null +++ b/Module3/GPLexProject/a.txt @@ -0,0 +1,3 @@ +begin ggg : ; :+= 7 99.9 5 +1 +ppp end diff --git a/Module3/GPLexProject/generateScanner.bat b/Module3/GPLexProject/generateScanner.bat new file mode 100644 index 0000000..e4f7d78 --- /dev/null +++ b/Module3/GPLexProject/generateScanner.bat @@ -0,0 +1 @@ +gplex.exe /noparser SimpleLex.lex \ No newline at end of file diff --git a/Module3/GPLexProject/mymain.cs b/Module3/GPLexProject/mymain.cs new file mode 100644 index 0000000..e00ca8b --- /dev/null +++ b/Module3/GPLexProject/mymain.cs @@ -0,0 +1,32 @@ +using System; +using System.IO; +using SimpleScanner; +using ScannerHelper; + +namespace Main +{ + class mymain + { + static void Main(string[] args) + { + // Чтобы вещественные числа распознавались и отображались в формате 3.14 (а не 3,14 как в русской Culture) + System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); + + var fname = @"..\..\a.txt"; + Console.WriteLine(File.ReadAllText(fname)); + Console.WriteLine("-------------------------"); + + Scanner scanner = new Scanner(new FileStream(fname, FileMode.Open)); + + int tok = 0; + do { + tok = scanner.yylex(); + if (tok == (int)Tok.EOF) + break; + Console.WriteLine(scanner.TokToString((Tok)tok)); + } while (true); + + Console.ReadKey(); + } + } +} diff --git a/Module5/SimpleLanguage0/Main.cs b/Module5/SimpleLanguage0/Main.cs new file mode 100644 index 0000000..b00452b --- /dev/null +++ b/Module5/SimpleLanguage0/Main.cs @@ -0,0 +1,45 @@ +п»їusing System; +using System.IO; +using System.Collections.Generic; +using SimpleScanner; +using SimpleParser; + +namespace SimpleCompiler +{ + public class SimpleCompilerMain + { + public static void Main() + { + string FileName = @"..\..\a.txt"; + try + { + string Text = File.ReadAllText(FileName); + + Scanner scanner = new Scanner(); + scanner.SetSource(Text, 0); + + Parser parser = new Parser(scanner); + + var b = parser.Parse(); + if (!b) + Console.WriteLine("Ошибка"); + else Console.WriteLine("Программа распознана"); + } + catch (FileNotFoundException) + { + Console.WriteLine("Файл {0} РЅРµ найден", FileName); + } + catch (LexException e) + { + Console.WriteLine("Лексическая ошибка. " + e.Message); + } + catch (SyntaxException e) + { + Console.WriteLine("Синтаксическая ошибка. " + e.Message); + } + + Console.ReadLine(); + } + + } +} diff --git a/Module5/SimpleLanguage0/ParserHelper.cs b/Module5/SimpleLanguage0/ParserHelper.cs new file mode 100644 index 0000000..4c781de --- /dev/null +++ b/Module5/SimpleLanguage0/ParserHelper.cs @@ -0,0 +1,19 @@ +п»їusing System; +using System.Linq; + +namespace SimpleParser +{ + public class LexException : Exception + { + public LexException(string msg) : base(msg) { } + } + public class SyntaxException : Exception + { + public SyntaxException(string msg) : base(msg) { } + } + // Класс глобальных описаний Рё статических методов + // для использования различными подсистемами парсера Рё сканера + public static class ParserHelper + { + } +} \ No newline at end of file diff --git a/Module5/SimpleLanguage0/Properties/AssemblyInfo.cs b/Module5/SimpleLanguage0/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..896cc99 --- /dev/null +++ b/Module5/SimpleLanguage0/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +п»їusing System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Управление общими сведениями Рѕ СЃР±РѕСЂРєРµ осуществляется СЃ помощью +// набора атрибутов. Рзмените значения этих атрибутов, чтобы изменить сведения, +// связанные СЃРѕ СЃР±РѕСЂРєРѕР№. +[assembly: AssemblyTitle("SimpleLang")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SimpleLang")] +[assembly: AssemblyCopyright("Copyright В© 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Параметр ComVisible СЃРѕ значением FALSE делает типы РІ СЃР±РѕСЂРєРµ невидимыми +// для COM-компонентов. Если требуется обратиться Рє типу РІ этой СЃР±РѕСЂРєРµ через +// COM, задайте атрибуту ComVisible значение TRUE для этого типа. +[assembly: ComVisible(false)] + +// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM +[assembly: Guid("06dba63f-4805-4cd3-8a93-b329b2c7e37b")] + +// Сведения Рѕ версии СЃР±РѕСЂРєРё состоят РёР· следующих четырех значений: +// +// РћСЃРЅРѕРІРЅРѕР№ номер версии +// Дополнительный номер версии +// Номер построения +// Редакция +// +// Можно задать РІСЃРµ значения или принять номер построения Рё номер редакции РїРѕ умолчанию, +// используя "*", как показано ниже: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Module5/SimpleLanguage0/ShiftReduceParserCode.cs b/Module5/SimpleLanguage0/ShiftReduceParserCode.cs new file mode 100644 index 0000000..c110ba1 --- /dev/null +++ b/Module5/SimpleLanguage0/ShiftReduceParserCode.cs @@ -0,0 +1,944 @@ +// Gardens Point Parser Generator +// Copyright (c) Wayne Kelly, QUT 2005-2009 +// (see accompanying GPPGcopyright.rtf) +#define EXPORT_GPPG + +using System; +using System.Text; +using System.Globalization; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; + +namespace QUT.Gppg +{ + /// <summary> + /// Abstract class for GPPG shift-reduce parsers. + /// Parsers generated by GPPG derive from this base + /// class, overriding the abstract Initialize() and + /// DoAction() methods. + /// </summary> + /// <typeparam name="TValue">Semantic value type</typeparam> + /// <typeparam name="TSpan">Location type</typeparam> +#if EXPORT_GPPG + public abstract class ShiftReduceParser<TValue, TSpan> +#else + internal abstract class ShiftReduceParser<TValue, TSpan> +#endif + where TSpan : IMerge<TSpan>, new() + { + public AbstractScanner<TValue, TSpan> scanner; + /// <summary> + /// The abstract scanner for this parser. + /// </summary> + protected AbstractScanner<TValue, TSpan> Scanner { + get { return scanner; } + set { scanner = value; } + } + + /// <summary> + /// Constructor for base class + /// </summary> + /// <param name="scanner">Scanner instance for this parser</param> + protected ShiftReduceParser(AbstractScanner<TValue, TSpan> scanner) + { + this.scanner = scanner; + } + + // ============================================================== + // TECHNICAL EXPLANATION. + // Why the next two fields are not exposed via properties. + // ============================================================== + // These fields are of the generic parameter types, and are + // frequently instantiated as struct types in derived classes. + // Semantic actions are defined in the derived classes and refer + // to instance fields of these structs. Is such cases the code + // "get_CurrentSemanticValue().myField = blah;" will fail since + // the getter pushes the value of the field, not the reference. + // So, in the presence of properties, gppg would need to encode + // such field accesses as ... + // "tmp = get_CurrentSemanticValue(); // Fetch value + // tmp.myField = blah; // update + // set_CurrentSemanticValue(tmp); " // Write update back. + // There is no issue if TValue is restricted to be a ref type. + // The same explanation applies to scanner.yylval. + // ============================================================== + /// <summary> + /// The current value of the "$$" symbolic variable in the parser + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + protected TValue CurrentSemanticValue; + + /// <summary> + /// The current value of the "@$" symbolic variable in the parser + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + protected TSpan CurrentLocationSpan; + + private TSpan LastSpan; + private int NextToken; + private State FsaState; + private bool recovering; + private int tokensSinceLastError; + + private PushdownPrefixState<State> StateStack = new PushdownPrefixState<State>(); + private PushdownPrefixState<TValue> valueStack = new PushdownPrefixState<TValue>(); + private PushdownPrefixState<TSpan> locationStack = new PushdownPrefixState<TSpan>(); + + /// <summary> + /// The stack of semantic value (YYSTYPE) values. + /// </summary> + protected PushdownPrefixState<TValue> ValueStack { get { return valueStack; } } + + /// <summary> + /// The stack of location value (YYLTYPE) varlues. + /// </summary> + protected PushdownPrefixState<TSpan> LocationStack { get { return locationStack; } } + + private int errorToken; + private int endOfFileToken; + private string[] nonTerminals; + private State[] states; + private Rule[] rules; + + /// <summary> + /// Initialization method to allow derived classes + /// to insert the rule list into this base class. + /// </summary> + /// <param name="rules">The array of Rule objects</param> + protected void InitRules(Rule[] rules) { this.rules = rules; } + + /// <summary> + /// Initialization method to allow derived classes to + /// insert the states table into this base class. + /// </summary> + /// <param name="states">The pre-initialized states table</param> + protected void InitStates(State[] states) { this.states = states; } + + /// <summary> + /// OBSOLETE FOR VERSION 1.4.0 + /// </summary> + /// <param name="size"></param> + protected void InitStateTable(int size) { states = new State[size]; } + + /// <summary> + /// Initialization method to allow derived classes + /// to insert the special value for the error and EOF tokens. + /// </summary> + /// <param name="err">The error state ordinal</param> + /// <param name="end">The EOF stat ordinal</param> + protected void InitSpecialTokens(int err, int end) + { + errorToken = err; + endOfFileToken = end; + } + + /// <summary> + /// Initialization method to allow derived classes to + /// insert the non-terminal symbol names into this base class. + /// </summary> + /// <param name="names">Non-terminal symbol names</param> + protected void InitNonTerminals(string[] names) { nonTerminals = names; } + + #region YYAbort, YYAccept etcetera. + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class AcceptException : Exception + { + internal AcceptException() { } + protected AcceptException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class AbortException : Exception + { + internal AbortException() { } + protected AbortException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class ErrorException : Exception + { + internal ErrorException() { } + protected ErrorException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + + // The following methods are only called from within + // a semantic action. The thrown exceptions can never + // propagate outside the ShiftReduceParser class in + // which they are nested. + + /// <summary> + /// Force parser to terminate, returning "true" + /// </summary> + protected static void YYAccept() { throw new AcceptException(); } + + /// <summary> + /// Force parser to terminate, returning "false" + /// </summary> + protected static void YYAbort() { throw new AbortException(); } + + /// <summary> + /// Force parser to terminate, returning + /// "false" if error recovery fails. + /// </summary> + protected static void YYError() { throw new ErrorException(); } + + /// <summary> + /// Check if parser in error recovery state. + /// </summary> + protected bool YYRecovering { get { return recovering; } } + #endregion + + /// <summary> + /// Abstract base method. ShiftReduceParser calls this + /// to initialize the base class data structures. Concrete + /// parser classes must override this method. + /// </summary> + protected abstract void Initialize(); + + /// <summary> + /// Main entry point of the Shift-Reduce Parser. + /// </summary> + /// <returns>True if parse succeeds, else false for + /// unrecoverable errors</returns> + public bool Parse() + { + Initialize(); // allow derived classes to instantiate rules, states and nonTerminals + + NextToken = 0; + FsaState = states[0]; + + StateStack.Push(FsaState); + valueStack.Push(CurrentSemanticValue); + LocationStack.Push(CurrentLocationSpan); + + while (true) + { +#if TRACE_ACTIONS + Console.Error.WriteLine("Entering state {0} ", FsaState.number); +#endif + int action = FsaState.defaultAction; + + if (FsaState.ParserTable != null) + { + if (NextToken == 0) + { +#if TRACE_ACTIONS + Console.Error.Write("Reading a token: "); +#endif + // We save the last token span, so that the location span + // of production right hand sides that begin or end with a + // nullable production will be correct. + LastSpan = scanner.yylloc; + NextToken = scanner.yylex(); + } + +#if TRACE_ACTIONS + Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken)); +#endif + if (FsaState.ParserTable.ContainsKey(NextToken)) + action = FsaState.ParserTable[NextToken]; + } + + if (action > 0) // shift + { + Shift(action); + } + else if (action < 0) // reduce + { + try + { + Reduce(-action); + if (action == -1) // accept + return true; + } + catch (Exception x) + { + if (x is AbortException) + return false; + else if (x is AcceptException) + return true; + else if (x is ErrorException && !ErrorRecovery()) + return false; + else + throw; // Rethrow x, preserving information. + + } + } + else if (action == 0) // error + if (!ErrorRecovery()) + return false; + } + } + + private void Shift(int stateIndex) + { +#if TRACE_ACTIONS + Console.Error.Write("Shifting token {0}, ", TerminalToString(NextToken)); +#endif + FsaState = states[stateIndex]; + + valueStack.Push(scanner.yylval); + StateStack.Push(FsaState); + LocationStack.Push(scanner.yylloc); + + if (recovering) + { + if (NextToken != errorToken) + tokensSinceLastError++; + + if (tokensSinceLastError > 5) + recovering = false; + } + + if (NextToken != endOfFileToken) + NextToken = 0; + } + + private void Reduce(int ruleNumber) + { +#if TRACE_ACTIONS + DisplayRule(ruleNumber); +#endif + Rule rule = rules[ruleNumber]; + // + // Default actions for unit productions. + // + if (rule.RightHandSide.Length == 1) + { + CurrentSemanticValue = valueStack.TopElement(); // Default action: $$ = $1; + CurrentLocationSpan = LocationStack.TopElement(); // Default action "@$ = @1; + } + else + { + if (rule.RightHandSide.Length == 0) + { + // Create a new blank value. + // Explicit semantic action may mutate this value + CurrentSemanticValue = default(TValue); + // The location span for an empty production will start with the + // beginning of the next lexeme, and end with the finish of the + // previous lexeme. This gives the correct behaviour when this + // nonsense value is used in later Merge operations. + CurrentLocationSpan = (scanner.yylloc != null && LastSpan != null ? + scanner.yylloc.Merge(LastSpan) : + default(TSpan)); + } + else + { + // Default action: $$ = $1; + CurrentSemanticValue = valueStack.TopElement(); + // Default action "@$ = @1.Merge(@N)" for location info. + TSpan at1 = LocationStack[LocationStack.Depth - rule.RightHandSide.Length]; + TSpan atN = LocationStack[LocationStack.Depth - 1]; + CurrentLocationSpan = + ((at1 != null && atN != null) ? at1.Merge(atN) : default(TSpan)); + } + } + + DoAction(ruleNumber); + + for (int i = 0; i < rule.RightHandSide.Length; i++) + { + StateStack.Pop(); + valueStack.Pop(); + LocationStack.Pop(); + } + +#if TRACE_ACTIONS + DisplayStack(); +#endif + FsaState = StateStack.TopElement(); + + if (FsaState.Goto.ContainsKey(rule.LeftHandSide)) + FsaState = states[FsaState.Goto[rule.LeftHandSide]]; + + StateStack.Push(FsaState); + valueStack.Push(CurrentSemanticValue); + LocationStack.Push(CurrentLocationSpan); + } + + /// <summary> + /// Execute the selected action from array. + /// Must be overriden in derived classes. + /// </summary> + /// <param name="actionNumber">Index of the action to perform</param> + protected abstract void DoAction(int actionNumber); + + private bool ErrorRecovery() + { + bool discard; + + if (!recovering) // if not recovering from previous error + ReportError(); + + if (!FindErrorRecoveryState()) + return false; + // + // The interim fix for the "looping in error recovery" + // artifact involved moving the setting of the recovering + // bool until after invalid tokens have been discarded. + // + ShiftErrorToken(); + discard = DiscardInvalidTokens(); + recovering = true; + tokensSinceLastError = 0; + return discard; + } + + private void ReportError1() + { + StringBuilder errorMsg = new StringBuilder(); + errorMsg.AppendFormat("Syntax error, unexpected {0}", TerminalToString(NextToken)); + + if (FsaState.ParserTable.Count < 7) + { + bool first = true; + foreach (int terminal in FsaState.ParserTable.Keys) + { + if (first) + errorMsg.Append(", expecting "); + else + errorMsg.Append(", or "); + + errorMsg.Append(TerminalToString(terminal)); + first = false; + } + } + scanner.yyerror(errorMsg.ToString()); + } + + private void ReportError() + { + object[] args = new object[FsaState.ParserTable.Keys.Count+1]; + args[0] = TerminalToString(NextToken); + int i=1; + foreach (int terminal in FsaState.ParserTable.Keys) + { + args[i] = TerminalToString(terminal); + i++; + } + scanner.yyerror("",args); + } + + private void ShiftErrorToken() + { + int old_next = NextToken; + NextToken = errorToken; + + Shift(FsaState.ParserTable[NextToken]); + +#if TRACE_ACTIONS + Console.Error.WriteLine("Entering state {0} ", FsaState.number); +#endif + NextToken = old_next; + } + + private bool FindErrorRecoveryState() + { + while (true) // pop states until one found that accepts error token + { + if (FsaState.ParserTable != null && + FsaState.ParserTable.ContainsKey(errorToken) && + FsaState.ParserTable[errorToken] > 0) // shift + return true; + +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: popping state {0}", StateStack.Top().number); +#endif + StateStack.Pop(); + valueStack.Pop(); + LocationStack.Pop(); + +#if TRACE_ACTIONS + DisplayStack(); +#endif + if (StateStack.IsEmpty()) + { +#if TRACE_ACTIONS + Console.Error.Write("Aborting: didn't find a state that accepts error token"); +#endif + return false; + } + else + FsaState = StateStack.TopElement(); + } + } + + private bool DiscardInvalidTokens() + { + + int action = FsaState.defaultAction; + + if (FsaState.ParserTable != null) + { + // Discard tokens until find one that works ... + while (true) + { + if (NextToken == 0) + { +#if TRACE_ACTIONS + Console.Error.Write("Reading a token: "); +#endif + NextToken = scanner.yylex(); + } + +#if TRACE_ACTIONS + Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken)); +#endif + if (NextToken == endOfFileToken) + return false; + + if (FsaState.ParserTable.ContainsKey(NextToken)) + action = FsaState.ParserTable[NextToken]; + + if (action != 0) + return true; + else + { +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: Discarding {0}", TerminalToString(NextToken)); +#endif + NextToken = 0; + } + } + } + else if (recovering && tokensSinceLastError == 0) + { + // + // Boolean recovering is not set until after the first + // error token has been shifted. Thus if we get back + // here with recovering set and no tokens read we are + // looping on the same error recovery action. This + // happens if current_state.ParserTable is null because + // the state has an LR(0) reduction, but not all + // lookahead tokens are valid. This only occurs for + // error productions that *end* on "error". + // + // This action discards tokens one at a time until + // the looping stops. Another attack would be to always + // use the LALR(1) table if a production ends on "error" + // +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: panic discard of {0}", TerminalToString(NextToken)); +#endif + if (NextToken == endOfFileToken) + return false; + NextToken = 0; + return true; + } + else + return true; + + } + + /// <summary> + /// Traditional YACC method. Discards the next input token. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyclearin")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyclearin")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + protected void yyclearin() { NextToken = 0; } + + /// <summary> + /// Tradional YACC method. Clear the "recovering" flag. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerrok")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerrok")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + protected void yyerrok() + { + recovering = false; + } + + /// <summary> + /// OBSOLETE FOR VERSION 1.4.0 + /// Method used by derived types to insert new + /// state instances in the "states" array. + /// </summary> + /// <param name="stateNumber">index of the state</param> + /// <param name="state">data for the state</param> + protected void AddState(int stateNumber, State state) + { + states[stateNumber] = state; + state.number = stateNumber; + } + + private void DisplayStack() + { + Console.Error.Write("State now"); + for (int i = 0; i < StateStack.Depth; i++) + Console.Error.Write(" {0}", StateStack[i].number); + Console.Error.WriteLine(); + } + + private void DisplayRule(int ruleNumber) + { + Console.Error.Write("Reducing stack by rule {0}, ", ruleNumber); + DisplayProduction(rules[ruleNumber]); + } + + private void DisplayProduction(Rule rule) + { + if (rule.RightHandSide.Length == 0) + Console.Error.Write("/* empty */ "); + else + foreach (int symbol in rule.RightHandSide) + Console.Error.Write("{0} ", SymbolToString(symbol)); + + Console.Error.WriteLine("-> {0}", SymbolToString(rule.LeftHandSide)); + } + + /// <summary> + /// Abstract state class naming terminal symbols. + /// This is overridden by derived classes with the + /// name (or alias) to be used in error messages. + /// </summary> + /// <param name="terminal">The terminal ordinal</param> + /// <returns></returns> + protected abstract string TerminalToString(int terminal); + + private string SymbolToString(int symbol) + { + if (symbol < 0) + return nonTerminals[-symbol]; + else + return TerminalToString(symbol); + } + + /// <summary> + /// Return text representation of argument character + /// </summary> + /// <param name="input">The character to convert</param> + /// <returns>String representation of the character</returns> + protected static string CharToString(char input) + { + switch (input) + { + case '\a': return @"'\a'"; + case '\b': return @"'\b'"; + case '\f': return @"'\f'"; + case '\n': return @"'\n'"; + case '\r': return @"'\r'"; + case '\t': return @"'\t'"; + case '\v': return @"'\v'"; + case '\0': return @"'\0'"; + default: return string.Format(CultureInfo.InvariantCulture, "'{0}'", input); + } + } + } + + /// <summary> + /// Classes implementing this interface must supply a + /// method that merges two location objects to return + /// a new object of the same type. + /// GPPG-generated parsers have the default location + /// action equivalent to "@$ = @1.Merge(@N);" where N + /// is the right-hand-side length of the production. + /// </summary> + /// <typeparam name="TSpan">The Location type</typeparam> +#if EXPORT_GPPG + public interface IMerge<TSpan> +#else + internal interface IMerge<TSpan> +#endif + { + /// <summary> + /// Interface method that creates a location object from + /// the current and last object. Typically used to create + /// a location object extending from the start of the @1 + /// object to the end of the @N object. + /// </summary> + /// <param name="last">The lexically last object to merge</param> + /// <returns>The merged location object</returns> + TSpan Merge(TSpan last); + } + + /// <summary> + /// This is the default class that carries location + /// information from the scanner to the parser. + /// If you don't declare "%YYLTYPE Foo" the parser + /// will expect to deal with this type. + /// </summary> +#if EXPORT_GPPG + public class LexLocation : IMerge<LexLocation> +#else + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + internal class LexLocation : IMerge<LexLocation> +#endif + { + private int startLine; // start line + private int startColumn; // start column + private int endLine; // end line + private int endColumn; // end column + + /// <summary> + /// The line at which the text span starts. + /// </summary> + public int StartLine { get { return startLine; } } + + /// <summary> + /// The column at which the text span starts. + /// </summary> + public int StartColumn { get { return startColumn; } } + + /// <summary> + /// The line on which the text span ends. + /// </summary> + public int EndLine { get { return endLine; } } + + /// <summary> + /// The column of the first character + /// beyond the end of the text span. + /// </summary> + public int EndColumn { get { return endColumn; } } + + /// <summary> + /// Default no-arg constructor. + /// </summary> + public LexLocation() + { } + + /// <summary> + /// Constructor for text-span with given start and end. + /// </summary> + /// <param name="sl">start line</param> + /// <param name="sc">start column</param> + /// <param name="el">end line </param> + /// <param name="ec">end column</param> + public LexLocation(int sl, int sc, int el, int ec) + { startLine = sl; startColumn = sc; endLine = el; endColumn = ec; } + + /// <summary> + /// Create a text location which spans from the + /// start of "this" to the end of the argument "last" + /// </summary> + /// <param name="last">The last location in the result span</param> + /// <returns>The merged span</returns> + public LexLocation Merge(LexLocation last) + { return new LexLocation(this.startLine, this.startColumn, last.endLine, last.endColumn); } + + } + + /// <summary> + /// Abstract scanner class that GPPG expects its scanners to + /// extend. + /// </summary> + /// <typeparam name="TValue">Semantic value type YYSTYPE</typeparam> + /// <typeparam name="TSpan">Source location type YYLTYPE</typeparam> +#if EXPORT_GPPG + public abstract class AbstractScanner<TValue, TSpan> +#else + internal abstract class AbstractScanner<TValue, TSpan> +#endif + where TSpan : IMerge<TSpan> + { + /// <summary> + /// Lexical value optionally set by the scanner. The value + /// is of the %YYSTYPE type declared in the parser spec. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylval")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylval")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + // A field must be declared for this value of parametric type, + // since it may be instantiated by a value struct. If it were + // implemented as a property, machine generated code in derived + // types would not be able to select on the returned value. + public TValue yylval; // Lexical value: set by scanner + + /// <summary> + /// Current scanner location property. The value is of the + /// type declared by %YYLTYPE in the parser specification. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylloc")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylloc")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public virtual TSpan yylloc + { + get { return default(TSpan); } // Empty implementation allowing + set { /* skip */ } // yylloc to be ignored entirely. + } + + /// <summary> + /// Main call point for LEX-like scanners. Returns an int + /// corresponding to the token recognized by the scanner. + /// </summary> + /// <returns>An int corresponding to the token</returns> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public abstract int yylex(); + + /// <summary> + /// Traditional error reporting provided by LEX-like scanners + /// to their YACC-like clients. + /// </summary> + /// <param name="format">Message format string</param> + /// <param name="args">Optional array of args</param> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerror")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerror")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public virtual void yyerror(string format, params object[] args) { } + } + + /// <summary> + /// Encapsulated state for the parser. + /// Opaque to users, visible to the tool-generated code. + /// </summary> +#if EXPORT_GPPG + public class State +#else + internal class State +#endif + { + internal int number; + internal Dictionary<int, int> ParserTable; // Terminal -> ParseAction + internal Dictionary<int, int> Goto; // NonTerminal -> State; + internal int defaultAction; // = 0; // ParseAction + + /// <summary> + /// State transition data for this state. Pairs of elements of the + /// goto array associate symbol ordinals with next state indices. + /// The actions array is passed to another constructor. + /// </summary> + /// <param name="actions">The action list</param> + /// <param name="goToList">Next state data</param> + public State(int[] actions, int[] goToList) + : this(actions) + { + Goto = new Dictionary<int, int>(); + for (int i = 0; i < goToList.Length; i += 2) + Goto.Add(goToList[i], goToList[i + 1]); + } + + /// <summary> + /// Action data for this state. Pairs of elements of the + /// action array associate action ordinals with each of + /// those symbols that have actions in the current state. + /// </summary> + /// <param name="actions">The action array</param> + public State(int[] actions) + { + ParserTable = new Dictionary<int, int>(); + for (int i = 0; i < actions.Length; i += 2) + ParserTable.Add(actions[i], actions[i + 1]); + } + + /// <summary> + /// Set the default action for this state. + /// </summary> + /// <param name="defaultAction">Ordinal of the default action</param> + public State(int defaultAction) + { + this.defaultAction = defaultAction; + } + + /// <summary> + /// Set the default action and the state transition table. + /// </summary> + /// <param name="defaultAction">The default action</param> + /// <param name="goToList">Transitions from this state</param> + public State(int defaultAction, int[] goToList) + : this(defaultAction) + { + Goto = new Dictionary<int, int>(); + for (int i = 0; i < goToList.Length; i += 2) + Goto.Add(goToList[i], goToList[i + 1]); + } + } + + /// <summary> + /// Rule representation at runtime. + /// </summary> +#if EXPORT_GPPG + public class Rule +#else + internal class Rule +#endif + { + internal int LeftHandSide; // symbol + internal int[] RightHandSide; // symbols + + /// <summary> + /// Rule constructor. This holds the ordinal of + /// the left hand side symbol, and the list of + /// right hand side symbols, in lexical order. + /// </summary> + /// <param name="left">The LHS non-terminal</param> + /// <param name="right">The RHS symbols, in lexical order</param> + public Rule(int left, int[] right) + { + this.LeftHandSide = left; + this.RightHandSide = right; + } + } + + /// <summary> + /// Stack utility for the shift-reduce parser. + /// GPPG parsers have three instances: + /// (1) The parser state stack, T = QUT.Gppg.State, + /// (2) The semantic value stack, T = TValue, + /// (3) The location stack, T = TSpan. + /// </summary> + /// <typeparam name="T"></typeparam> +#if EXPORT_GPPG + public class PushdownPrefixState<T> +#else + internal class PushdownPrefixState<T> +#endif + { + // Note that we cannot use the BCL Stack<T> class + // here as derived types need to index into stacks. + // + private T[] array = new T[8]; + private int tos = 0; + + /// <summary> + /// Indexer for values of the stack below the top. + /// </summary> + /// <param name="index">index of the element, starting from the bottom</param> + /// <returns>the selected element</returns> + public T this[int index] { get { return array[index]; } } + + /// <summary> + /// The current depth of the stack. + /// </summary> + public int Depth { get { return tos; } } + + internal void Push(T value) + { + if (tos >= array.Length) + { + T[] newarray = new T[array.Length * 2]; + System.Array.Copy(array, newarray, tos); + array = newarray; + } + array[tos++] = value; + } + + internal T Pop() + { + T rslt = array[--tos]; + array[tos] = default(T); + return rslt; + } + + internal T TopElement() { return array[tos - 1]; } + + internal bool IsEmpty() { return tos == 0; } + } +} \ No newline at end of file diff --git a/Module5/SimpleLanguage0/SimpleLang.csproj b/Module5/SimpleLanguage0/SimpleLang.csproj new file mode 100644 index 0000000..a45c176 --- /dev/null +++ b/Module5/SimpleLanguage0/SimpleLang.csproj @@ -0,0 +1,61 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>SimpleLang</RootNamespace> + <AssemblyName>SimpleLang</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Main.cs" /> + <Compile Include="ParserHelper.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="ShiftReduceParserCode.cs" /> + <Compile Include="SimpleLex.cs" /> + <Compile Include="SimpleYacc.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project> \ No newline at end of file diff --git a/Module5/SimpleLanguage0/SimpleLang.sln b/Module5/SimpleLanguage0/SimpleLang.sln new file mode 100644 index 0000000..0f586d1 --- /dev/null +++ b/Module5/SimpleLanguage0/SimpleLang.sln @@ -0,0 +1,20 @@ +п»ї +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleLang", "SimpleLang.csproj", "{12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Debug|x86.ActiveCfg = Debug|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Debug|x86.Build.0 = Debug|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Release|x86.ActiveCfg = Release|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Module5/SimpleLanguage0/SimpleLex.cs b/Module5/SimpleLanguage0/SimpleLex.cs new file mode 100644 index 0000000..7752281 --- /dev/null +++ b/Module5/SimpleLanguage0/SimpleLex.cs @@ -0,0 +1,1485 @@ +// +// This CSharp output file generated by Gardens Point LEX +// Version: 1.1.3.301 +// Machine: HUB +// DateTime: 21.09.2017 20:15:13 +// UserName: someone +// GPLEX input file <SimpleLex.lex> +// GPLEX frame file <embedded resource> +// +// Option settings: unicode, parser, minimize +// Option settings: classes, compressMap, compressNext, persistBuffer, embedbuffers +// Fallback code page: Target machine default +// + +// +// Experimental embedded frame +// Version 1.1.3 of 18-April-2010 +// +// +#define BACKUP +#define PERSIST + +using System; +using System.IO; +using System.Text; +using System.Globalization; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; + +using SimpleParser; +using QUT.Gppg; +using System.Linq; + +namespace SimpleScanner +{ + /// <summary> + /// Summary Canonical example of GPLEX automaton + /// </summary> + +#if STANDALONE + // + // These are the dummy declarations for stand-alone GPLEX applications + // normally these declarations would come from the parser. + // If you declare /noparser, or %option noparser then you get this. + // + + public enum Tokens + { + EOF = 0, maxParseToken = int.MaxValue + // must have at least these two, values are almost arbitrary + } + + public abstract class ScanBase + { + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + public abstract int yylex(); + + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yywrap")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yywrap")] + protected virtual bool yywrap() { return true; } + +#if BABEL + protected abstract int CurrentSc { get; set; } + // EolState is the 32-bit of state data persisted at + // the end of each line for Visual Studio colorization. + // The default is to return CurrentSc. You must override + // this if you want more complicated behavior. + public virtual int EolState { + get { return CurrentSc; } + set { CurrentSc = value; } + } + } + + public interface IColorScan + { + void SetSource(string source, int offset); + int GetNext(ref int state, out int start, out int end); +#endif // BABEL + } + +#endif // STANDALONE + + // If the compiler can't find the scanner base class maybe you + // need to run GPPG with the /gplex option, or GPLEX with /noparser +#if BABEL + public sealed partial class Scanner : ScanBase, IColorScan + { + private ScanBuff buffer; + int currentScOrd; // start condition ordinal + + protected override int CurrentSc + { + // The current start state is a property + // to try to avoid the user error of setting + // scState but forgetting to update the FSA + // start state "currentStart" + // + get { return currentScOrd; } // i.e. return YY_START; + set { currentScOrd = value; // i.e. BEGIN(value); + currentStart = startState[value]; } + } +#else // BABEL + public sealed partial class Scanner : ScanBase + { + private ScanBuff buffer; + int currentScOrd; // start condition ordinal +#endif // BABEL + + /// <summary> + /// The input buffer for this scanner. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public ScanBuff Buffer { get { return buffer; } } + + private static int GetMaxParseToken() { + System.Reflection.FieldInfo f = typeof(Tokens).GetField("maxParseToken"); + return (f == null ? int.MaxValue : (int)f.GetValue(null)); + } + + static int parserMax = GetMaxParseToken(); + + enum Result {accept, noMatch, contextFound}; + + const int maxAccept = 7; + const int initial = 8; + const int eofNum = 0; + const int goStart = -1; + const int INITIAL = 0; + +#region user code +#endregion user code + + int state; + int currentStart = startState[0]; + int code; // last code read + int cCol; // column number of code + int lNum; // current line number + // + // The following instance variables are used, among other + // things, for constructing the yylloc location objects. + // + int tokPos; // buffer position at start of token + int tokCol; // zero-based column number at start of token + int tokLin; // line number at start of token + int tokEPos; // buffer position at end of token + int tokECol; // column number at end of token + int tokELin; // line number at end of token + string tokTxt; // lazily constructed text of token +#if STACK + private Stack<int> scStack = new Stack<int>(); +#endif // STACK + +#region ScannerTables + struct Table { + public int min; public int rng; public int dflt; + public sbyte[] nxt; + public Table(int m, int x, int d, sbyte[] n) { + min = m; rng = x; dflt = d; nxt = n; + } + }; + + static int[] startState = new int[] {8, 0}; + +#region CompressedCharacterMap + // + // There are 8 equivalence classes + // There are 2 character sequence regions + // There are 1 tables, 123 entries + // There are 1 runs, 0 singletons + // Decision tree depth is 1 + // + static sbyte[] mapC0 = new sbyte[123] { +/* '\0' */ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 0, 7, 7, +/* '\x10' */ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +/* '\x20' */ 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, +/* '0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 6, 7, 5, 7, 7, +/* '@' */ 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* 'P' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 3, +/* '`' */ 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* 'p' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; + + static sbyte MapC(int code) + { // '\0' <= code <= '\U0010FFFF' + if (code < 123) // '\0' <= code <= 'z' + return mapC0[code - 0]; + else // '{' <= code <= '\U0010FFFF' + return (sbyte)7; + } +#endregion + + static Table[] NxS = new Table[10] { +/* NxS[ 0] */ new Table(0, 0, 0, null), +/* NxS[ 1] */ new Table(1, 2, -1, new sbyte[] {1, 9}), +/* NxS[ 2] */ new Table(0, 0, -1, null), +/* NxS[ 3] */ new Table(1, 3, -1, new sbyte[] {3, -1, 3}), +/* NxS[ 4] */ new Table(5, 1, -1, new sbyte[] {6}), +/* NxS[ 5] */ new Table(0, 0, -1, null), +/* NxS[ 6] */ new Table(0, 0, -1, null), +/* NxS[ 7] */ new Table(1, 1, -1, new sbyte[] {7}), +/* NxS[ 8] */ new Table(1, 7, -1, new sbyte[] {1, 2, 3, 4, 2, 5, + 2}), +/* NxS[ 9] */ new Table(1, 1, -1, new sbyte[] {7}), + }; + +int NextState() { + if (code == ScanBuff.EndOfFile) + return eofNum; + else + unchecked { + int rslt; + int idx = MapC(code) - NxS[state].min; + if (idx < 0) idx += 8; + if ((uint)idx >= (uint)NxS[state].rng) rslt = NxS[state].dflt; + else rslt = NxS[state].nxt[idx]; + return rslt; + } +} + +#endregion + + +#if BACKUP + // ============================================================== + // == Nested struct used for backup in automata that do backup == + // ============================================================== + + struct Context // class used for automaton backup. + { + public int bPos; + public int rPos; // scanner.readPos saved value + public int cCol; + public int lNum; // Need this in case of backup over EOL. + public int state; + public int cChr; + } + + private Context ctx = new Context(); +#endif // BACKUP + + // ============================================================== + // ==== Nested struct to support input switching in scanners ==== + // ============================================================== + + struct BufferContext { + internal ScanBuff buffSv; + internal int chrSv; + internal int cColSv; + internal int lNumSv; + } + + // ============================================================== + // ===== Private methods to save and restore buffer contexts ==== + // ============================================================== + + /// <summary> + /// This method creates a buffer context record from + /// the current buffer object, together with some + /// scanner state values. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + BufferContext MkBuffCtx() + { + BufferContext rslt; + rslt.buffSv = this.buffer; + rslt.chrSv = this.code; + rslt.cColSv = this.cCol; + rslt.lNumSv = this.lNum; + return rslt; + } + + /// <summary> + /// This method restores the buffer value and allied + /// scanner state from the given context record value. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void RestoreBuffCtx(BufferContext value) + { + this.buffer = value.buffSv; + this.code = value.chrSv; + this.cCol = value.cColSv; + this.lNum = value.lNumSv; + } + // =================== End Nested classes ======================= + +#if !NOFILES + public Scanner(Stream file) { + SetSource(file, 0); // unicode option + } + + public Scanner(Stream file, string codepage) { + SetSource(file, CodePageHandling.GetCodePage(codepage)); + } + +#endif // !NOFILES + + public Scanner() { } + + private int readPos; + + void GetCode() + { + if (code == '\n') // This needs to be fixed for other conventions + // i.e. [\r\n\205\u2028\u2029] + { + cCol = -1; + lNum++; + } + readPos = buffer.Pos; + + // Now read new codepoint. + code = buffer.Read(); + if (code > ScanBuff.EndOfFile) + { +#if (!BYTEMODE) + if (code >= 0xD800 && code <= 0xDBFF) + { + int next = buffer.Read(); + if (next < 0xDC00 || next > 0xDFFF) + code = ScanBuff.UnicodeReplacementChar; + else + code = (0x10000 + (code & 0x3FF << 10) + (next & 0x3FF)); + } +#endif + cCol++; + } + } + + void MarkToken() + { +#if (!PERSIST) + buffer.Mark(); +#endif + tokPos = readPos; + tokLin = lNum; + tokCol = cCol; + } + + void MarkEnd() + { + tokTxt = null; + tokEPos = readPos; + tokELin = lNum; + tokECol = cCol; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int Peek() + { + int rslt, codeSv = code, cColSv = cCol, lNumSv = lNum, bPosSv = buffer.Pos; + GetCode(); rslt = code; + lNum = lNumSv; cCol = cColSv; code = codeSv; buffer.Pos = bPosSv; + return rslt; + } + + // ============================================================== + // ===== Initialization of string-based input buffers ==== + // ============================================================== + + /// <summary> + /// Create and initialize a StringBuff buffer object for this scanner + /// </summary> + /// <param name="source">the input string</param> + /// <param name="offset">starting offset in the string</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(string source, int offset) + { + this.buffer = ScanBuff.GetBuffer(source); + this.buffer.Pos = offset; + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } + +#if !NOFILES + // ================ LineBuffer Initialization =================== + + /// <summary> + /// Create and initialize a LineBuff buffer object for this scanner + /// </summary> + /// <param name="source">the list of input strings</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(IList<string> source) + { + this.buffer = ScanBuff.GetBuffer(source); + this.code = '\n'; // to initialize yyline, yycol and lineStart + this.lNum = 0; + GetCode(); + } + + // =============== StreamBuffer Initialization ================== + + /// <summary> + /// Create and initialize a StreamBuff buffer object for this scanner. + /// StreamBuff is buffer for 8-bit byte files. + /// </summary> + /// <param name="source">the input byte stream</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(Stream source) + { + this.buffer = ScanBuff.GetBuffer(source); + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } + +#if !BYTEMODE + // ================ TextBuffer Initialization =================== + + /// <summary> + /// Create and initialize a TextBuff buffer object for this scanner. + /// TextBuff is a buffer for encoded unicode files. + /// </summary> + /// <param name="source">the input text file</param> + /// <param name="fallbackCodePage">Code page to use if file has + /// no BOM. For 0, use machine default; for -1, 8-bit binary</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(Stream source, int fallbackCodePage) + { + this.buffer = ScanBuff.GetBuffer(source, fallbackCodePage); + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } +#endif // !BYTEMODE +#endif // !NOFILES + + // ============================================================== + +#if BABEL + // + // Get the next token for Visual Studio + // + // "state" is the inout mode variable that maintains scanner + // state between calls, using the EolState property. In principle, + // if the calls of EolState are costly set could be called once + // only per line, at the start; and get called only at the end + // of the line. This needs more infrastructure ... + // + public int GetNext(ref int state, out int start, out int end) + { + Tokens next; + int s, e; + s = state; // state at start + EolState = state; + next = (Tokens)Scan(); + state = EolState; + e = state; // state at end; + start = tokPos; + end = tokEPos - 1; // end is the index of last char. + return (int)next; + } +#endif // BABEL + + // ======== AbstractScanner<> Implementation ========= + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + public override int yylex() + { + // parserMax is set by reflecting on the Tokens + // enumeration. If maxParseToken is defined + // that is used, otherwise int.MaxValue is used. + int next; + do { next = Scan(); } while (next >= parserMax); + return next; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yypos { get { return tokPos; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yyline { get { return tokLin; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yycol { get { return tokCol; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yytext")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yytext")] + public string yytext + { + get + { + if (tokTxt == null) + tokTxt = buffer.GetString(tokPos, tokEPos); + return tokTxt; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void yyless(int n) + { + buffer.Pos = tokPos; + // Must read at least one char, so set before start. + cCol = tokCol - 1; + GetCode(); + // Now ensure that line counting is correct. + lNum = tokLin; + // And count the rest of the text. + for (int i = 0; i < n; i++) GetCode(); + MarkEnd(); + } + + // + // It would be nice to count backward in the text + // but it does not seem possible to re-establish + // the correct column counts except by going forward. + // + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void _yytrunc(int n) { yyless(yyleng - n); } + + // + // This is painful, but we no longer count + // codepoints. For the overwhelming majority + // of cases the single line code is fast, for + // the others, well, at least it is all in the + // buffer so no files are touched. Note that we + // can't use (tokEPos - tokPos) because of the + // possibility of surrogate pairs in the token. + // + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyleng")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyleng")] + public int yyleng + { + get { +#if BYTEMODE + return tokEPos - tokPos; +#else + if (tokELin == tokLin) + return tokECol - tokCol; + else { + int ch; + int count = 0; + int save = buffer.Pos; + buffer.Pos = tokPos; + do { + ch = buffer.Read(); + if (!char.IsHighSurrogate((char)ch)) count++; + } while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile); + buffer.Pos = save; + return count; + } +#endif // BYTEMODE + } + } + + // ============ methods available in actions ============== + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal int YY_START { + get { return currentScOrd; } + set { currentScOrd = value; + currentStart = startState[value]; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void BEGIN(int next) { + currentScOrd = next; + currentStart = startState[next]; + } + + // ============== The main tokenizer code ================= + + int Scan() + { + try { + for (; ; ) + { + int next; // next state to enter +#if BACKUP + Result rslt = Result.noMatch; +#endif // BACKUP +#if LEFTANCHORS + for (;;) + { + // Discard characters that do not start any pattern. + // Must check the left anchor condition after *every* GetCode! + state = ((cCol == 0) ? anchorState[currentScOrd] : currentStart); + if ((next = NextState()) != goStart) + break; // LOOP EXIT HERE... + GetCode(); + } + +#else // !LEFTANCHORS + state = currentStart; + while ((next = NextState()) == goStart) + // At this point, the current character has no + // transition from the current state. We discard + // the "no-match" char. In traditional LEX such + // characters are echoed to the console. + GetCode(); +#endif // LEFTANCHORS + // At last, a valid transition ... + MarkToken(); + state = next; + GetCode(); + + while ((next = NextState()) > eofNum) // Exit for goStart AND for eofNum +#if BACKUP + if (state <= maxAccept && next > maxAccept) // need to prepare backup data + { + // ctx is an object. The fields may be + // mutated by the call to Recurse2. + // On return the data in ctx is the + // *latest* accept state that was found. + + rslt = Recurse2(ref ctx, next); + if (rslt == Result.noMatch) + RestoreStateAndPos(ref ctx); + break; + } + else +#endif // BACKUP + { + state = next; + GetCode(); + } + if (state <= maxAccept) + { + MarkEnd(); +#region ActionSwitch +#pragma warning disable 162 + switch (state) + { + case eofNum: + if (yywrap()) + return (int)Tokens.EOF; + break; + case 1: +return (int)Tokens.INUM; + break; + case 2: + case 4: +LexError(); + return (int)Tokens.EOF; + break; + case 3: +int res = ScannerHelper.GetIDToken(yytext); + return res; + break; + case 5: +return (int)Tokens.SEMICOLON; + break; + case 6: +return (int)Tokens.ASSIGN; + break; + case 7: +return (int)Tokens.RNUM; + break; + default: + break; + } +#pragma warning restore 162 +#endregion + } + } + } // end try + finally { +// User-specified epilog to scan() +yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); +// End, user-specified epilog + } // end finally + } + +#if BACKUP + Result Recurse2(ref Context ctx, int next) + { + // Assert: at entry "state" is an accept state AND + // NextState(state, code) != goStart AND + // NextState(state, code) is not an accept state. + // + SaveStateAndPos(ref ctx); + state = next; + GetCode(); + + while ((next = NextState()) > eofNum) + { + if (state <= maxAccept && next > maxAccept) // need to update backup data + SaveStateAndPos(ref ctx); + state = next; + if (state == eofNum) return Result.accept; + GetCode(); + } + return (state <= maxAccept ? Result.accept : Result.noMatch); + } + + void SaveStateAndPos(ref Context ctx) + { + ctx.bPos = buffer.Pos; + ctx.rPos = readPos; + ctx.cCol = cCol; + ctx.lNum = lNum; + ctx.state = state; + ctx.cChr = code; + } + + void RestoreStateAndPos(ref Context ctx) + { + buffer.Pos = ctx.bPos; + readPos = ctx.rPos; + cCol = ctx.cCol; + lNum = ctx.lNum; + state = ctx.state; + code = ctx.cChr; + } + +#endif // BACKUP + + // ============= End of the tokenizer code ================ + +#if STACK + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void yy_clear_stack() { scStack.Clear(); } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal int yy_top_state() { return scStack.Peek(); } + + internal void yy_push_state(int state) + { + scStack.Push(currentScOrd); + BEGIN(state); + } + + internal void yy_pop_state() + { + // Protect against input errors that pop too far ... + if (scStack.Count > 0) { + int newSc = scStack.Pop(); + BEGIN(newSc); + } // Otherwise leave stack unchanged. + } + #endif // STACK + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void ECHO() { Console.Out.Write(yytext); } + +#region UserCodeSection + +public override void yyerror(string format, params object[] args) // обработка синтаксических ошибок +{ + var ww = args.Skip(1).Cast<string>().ToArray(); + string errorMsg = string.Format("({0},{1}): Встречено {2}, а ожидалось {3}", yyline, yycol, args[0], string.Join(" или ", ww)); + throw new SyntaxException(errorMsg); +} + +public void LexError() +{ + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); + throw new LexException(errorMsg); +} + +class ScannerHelper +{ + private static Dictionary<string,int> keywords; + + static ScannerHelper() + { + keywords = new Dictionary<string,int>(); + keywords.Add("begin",(int)Tokens.BEGIN); + keywords.Add("end",(int)Tokens.END); + keywords.Add("cycle",(int)Tokens.CYCLE); + } + public static int GetIDToken(string s) + { + if (keywords.ContainsKey(s.ToLower())) // язык нечувствителен к регистру + return keywords[s]; + else + return (int)Tokens.ID; + } +} + +#endregion + } // end class $Scanner + +// ============================================================== +// <auto-generated> +// This code automatically produced from an embedded resource. +// Do not edit this file, or it will become incompatible with +// the specification from which it was generated. +// </auto-generated> +// ============================================================== + +// Code copied from GPLEX embedded resource + [Serializable] + public class BufferException : Exception + { + public BufferException() { } + public BufferException(string message) : base(message) { } + public BufferException(string message, Exception innerException) + : base(message, innerException) { } + protected BufferException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + } + + public abstract class ScanBuff + { + private string fileNm; + + public const int EndOfFile = -1; + public const int UnicodeReplacementChar = 0xFFFD; + + public bool IsFile { get { return (fileNm != null); } } + public string FileName { get { return fileNm; } set { fileNm = value; } } + + public abstract int Pos { get; set; } + public abstract int Read(); + public virtual void Mark() { } + + public abstract string GetString(int begin, int limit); + + public static ScanBuff GetBuffer(string source) + { + return new StringBuffer(source); + } + + public static ScanBuff GetBuffer(IList<string> source) + { + return new LineBuffer(source); + } + + public static ScanBuff GetBuffer(Stream source) + { + return new BuildBuffer(source); + } + +#if (!BYTEMODE) + public static ScanBuff GetBuffer(Stream source, int fallbackCodePage) + { + return new BuildBuffer(source, fallbackCodePage); + } +#endif + } + + #region Buffer classes + + // ============================================================== + // ===== Definitions for various ScanBuff derived classes ==== + // ============================================================== + // =============== String input ================ + // ============================================================== + + /// <summary> + /// This class reads characters from a single string as + /// required, for example, by Visual Studio language services + /// </summary> + sealed class StringBuffer : ScanBuff + { + string str; // input buffer + int bPos; // current position in buffer + int sLen; + + public StringBuffer(string source) + { + this.str = source; + this.sLen = source.Length; + this.FileName = null; + } + + public override int Read() + { + if (bPos < sLen) return str[bPos++]; + else if (bPos == sLen) { bPos++; return '\n'; } // one strike, see new line + else { bPos++; return EndOfFile; } // two strikes and you're out! + } + + public override string GetString(int begin, int limit) + { + // "limit" can be greater than sLen with the BABEL + // option set. Read returns a "virtual" EOL if + // an attempt is made to read past the end of the + // string buffer. Without the guard any attempt + // to fetch yytext for a token that includes the + // EOL will throw an index exception. + if (limit > sLen) limit = sLen; + if (limit <= begin) return ""; + else return str.Substring(begin, limit - begin); + } + + public override int Pos + { + get { return bPos; } + set { bPos = value; } + } + + public override string ToString() { return "StringBuffer"; } + } + + // ============================================================== + // The LineBuff class contributed by Nigel Horspool, + // nigelh@cs.uvic.cs + // ============================================================== + + sealed class LineBuffer : ScanBuff + { + IList<string> line; // list of source lines from a file + int numLines; // number of strings in line list + string curLine; // current line in that list + int cLine; // index of current line in the list + int curLen; // length of current line + int curLineStart; // position of line start in whole file + int curLineEnd; // position of line end in whole file + int maxPos; // max position ever visited in whole file + int cPos; // ordinal number of code in source + + // Constructed from a list of strings, one per source line. + // The lines have had trailing '\n' characters removed. + public LineBuffer(IList<string> lineList) + { + line = lineList; + numLines = line.Count; + cPos = curLineStart = 0; + curLine = (numLines > 0 ? line[0] : ""); + maxPos = curLineEnd = curLen = curLine.Length; + cLine = 1; + FileName = null; + } + + public override int Read() + { + if (cPos < curLineEnd) + return curLine[cPos++ - curLineStart]; + if (cPos++ == curLineEnd) + return '\n'; + if (cLine >= numLines) + return EndOfFile; + curLine = line[cLine]; + curLen = curLine.Length; + curLineStart = curLineEnd + 1; + curLineEnd = curLineStart + curLen; + if (curLineEnd > maxPos) + maxPos = curLineEnd; + cLine++; + return curLen > 0 ? curLine[0] : '\n'; + } + + // To speed up searches for the line containing a position + private int cachedPosition; + private int cachedIxdex; + private int cachedLineStart; + + // Given a position pos within the entire source, the results are + // ix -- the index of the containing line + // lstart -- the position of the first character on that line + private void findIndex(int pos, out int ix, out int lstart) + { + if (pos >= cachedPosition) + { + ix = cachedIxdex; lstart = cachedLineStart; + } + else + { + ix = lstart = 0; + } + for (; ; ) + { + int len = line[ix].Length + 1; + if (pos < lstart + len) break; + lstart += len; + ix++; + } + cachedPosition = pos; + cachedIxdex = ix; + cachedLineStart = lstart; + } + + public override string GetString(int begin, int limit) + { + if (begin >= maxPos || limit <= begin) return ""; + int endIx, begIx, endLineStart, begLineStart; + findIndex(begin, out begIx, out begLineStart); + int begCol = begin - begLineStart; + findIndex(limit, out endIx, out endLineStart); + int endCol = limit - endLineStart; + string s = line[begIx]; + if (begIx == endIx) + { + // the usual case, substring all on one line + return (endCol <= s.Length) ? + s.Substring(begCol, endCol - begCol) + : s.Substring(begCol) + "\n"; + } + // the string spans multiple lines, yuk! + StringBuilder sb = new StringBuilder(); + if (begCol < s.Length) + sb.Append(s.Substring(begCol)); + for (; ; ) + { + sb.Append("\n"); + s = line[++begIx]; + if (begIx >= endIx) break; + sb.Append(s); + } + if (endCol <= s.Length) + { + sb.Append(s.Substring(0, endCol)); + } + else + { + sb.Append(s); + sb.Append("\n"); + } + return sb.ToString(); + } + + public override int Pos + { + get { return cPos; } + set + { + cPos = value; + findIndex(cPos, out cLine, out curLineStart); + curLine = line[cLine]; + curLineEnd = curLineStart + curLine.Length; + } + } + + public override string ToString() { return "LineBuffer"; } + } + + + // ============================================================== + // ===== class BuildBuff : for unicode text files ======== + // ============================================================== + + class BuildBuffer : ScanBuff + { + // Double buffer for char stream. + class BufferElement + { + StringBuilder bldr = new StringBuilder(); + StringBuilder next = new StringBuilder(); + int minIx; + int maxIx; + int brkIx; + bool appendToNext; + + internal BufferElement() { } + + internal int MaxIndex { get { return maxIx; } } + // internal int MinIndex { get { return minIx; } } + + internal char this[int index] + { + get + { + if (index < minIx || index >= maxIx) + throw new BufferException("Index was outside data buffer"); + else if (index < brkIx) + return bldr[index - minIx]; + else + return next[index - brkIx]; + } + } + + internal void Append(char[] block, int count) + { + maxIx += count; + if (appendToNext) + this.next.Append(block, 0, count); + else + { + this.bldr.Append(block, 0, count); + brkIx = maxIx; + appendToNext = true; + } + } + + internal string GetString(int start, int limit) + { + if (limit <= start) + return ""; + if (start >= minIx && limit <= maxIx) + if (limit < brkIx) // String entirely in bldr builder + return bldr.ToString(start - minIx, limit - start); + else if (start >= brkIx) // String entirely in next builder + return next.ToString(start - brkIx, limit - start); + else // Must do a string-concatenation + return + bldr.ToString(start - minIx, brkIx - start) + + next.ToString(0, limit - brkIx); + else + throw new BufferException("String was outside data buffer"); + } + + internal void Mark(int limit) + { + if (limit > brkIx + 16) // Rotate blocks + { + StringBuilder temp = bldr; + bldr = next; + next = temp; + next.Length = 0; + minIx = brkIx; + brkIx = maxIx; + } + } + } + + BufferElement data = new BufferElement(); + + int bPos; // Postion index in the StringBuilder + BlockReader NextBlk; // Delegate that serves char-arrays; + + private string EncodingName + { + get + { + StreamReader rdr = NextBlk.Target as StreamReader; + return (rdr == null ? "raw-bytes" : rdr.CurrentEncoding.BodyName); + } + } + + public BuildBuffer(Stream stream) + { + FileStream fStrm = (stream as FileStream); + if (fStrm != null) FileName = fStrm.Name; + NextBlk = BlockReaderFactory.Raw(stream); + } + +#if (!BYTEMODE) + public BuildBuffer(Stream stream, int fallbackCodePage) + { + FileStream fStrm = (stream as FileStream); + if (fStrm != null) FileName = fStrm.Name; + NextBlk = BlockReaderFactory.Get(stream, fallbackCodePage); + } +#endif + + /// <summary> + /// Marks a conservative lower bound for the buffer, + /// allowing space to be reclaimed. If an application + /// needs to call GetString at arbitrary past locations + /// in the input stream, Mark() is not called. + /// </summary> + public override void Mark() { data.Mark(bPos - 2); } + + public override int Pos + { + get { return bPos; } + set { bPos = value; } + } + + + /// <summary> + /// Read returns the ordinal number of the next char, or + /// EOF (-1) for an end of stream. Note that the next + /// code point may require *two* calls of Read(). + /// </summary> + /// <returns></returns> + public override int Read() + { + // + // Characters at positions + // [data.offset, data.offset + data.bldr.Length) + // are available in data.bldr. + // + if (bPos < data.MaxIndex) + { + // ch0 cannot be EOF + return (int)data[bPos++]; + } + else // Read from underlying stream + { + // Experimental code, blocks of page size + char[] chrs = new char[4096]; + int count = NextBlk(chrs, 0, 4096); + if (count == 0) + return EndOfFile; + else + { + data.Append(chrs, count); + return (int)data[bPos++]; + } + } + } + + public override string GetString(int begin, int limit) + { + return data.GetString(begin, limit); + } + + public override string ToString() + { + return "StringBuilder buffer, encoding: " + this.EncodingName; + } + } + + // =============== End ScanBuff-derived classes ================== + + public delegate int BlockReader(char[] block, int index, int number); + + // A delegate factory, serving up a delegate that + // reads a block of characters from the underlying + // encoded stream, via a StreamReader object. + // + public static class BlockReaderFactory + { + public static BlockReader Raw(Stream stream) + { + return delegate(char[] block, int index, int number) + { + byte[] b = new byte[number]; + int count = stream.Read(b, 0, number); + int i = 0; + int j = index; + for (; i < count; i++, j++) + block[j] = (char)b[i]; + return count; + }; + } + +#if (!BYTEMODE) + public static BlockReader Get(Stream stream, int fallbackCodePage) + { + Encoding encoding; + int preamble = Preamble(stream); + + if (preamble != 0) // There is a valid BOM here! + encoding = Encoding.GetEncoding(preamble); + else if (fallbackCodePage == -1) // Fallback is "raw" bytes + return Raw(stream); + else if (fallbackCodePage != -2) // Anything but "guess" + encoding = Encoding.GetEncoding(fallbackCodePage); + else // This is the "guess" option + { + int guess = new Guesser(stream).GuessCodePage(); + stream.Seek(0, SeekOrigin.Begin); + if (guess == -1) // ==> this is a 7-bit file + encoding = Encoding.ASCII; + else if (guess == 65001) + encoding = Encoding.UTF8; + else // ==> use the machine default + encoding = Encoding.Default; + } + StreamReader reader = new StreamReader(stream, encoding); + return reader.Read; + } + + static int Preamble(Stream stream) + { + int b0 = stream.ReadByte(); + int b1 = stream.ReadByte(); + + if (b0 == 0xfe && b1 == 0xff) + return 1201; // UTF16BE + if (b0 == 0xff && b1 == 0xfe) + return 1200; // UTF16LE + + int b2 = stream.ReadByte(); + if (b0 == 0xef && b1 == 0xbb && b2 == 0xbf) + return 65001; // UTF8 + // + // There is no unicode preamble, so we + // return denoter for the machine default. + // + stream.Seek(0, SeekOrigin.Begin); + return 0; + } +#endif // !BYTEMODE + } + #endregion Buffer classes + + // ============================================================== + // ============ class CodePageHandling ============= + // ============================================================== + + public static class CodePageHandling + { + public static int GetCodePage(string option) + { + string command = option.ToUpperInvariant(); + if (command.StartsWith("CodePage:", StringComparison.OrdinalIgnoreCase)) + command = command.Substring(9); + try + { + if (command.Equals("RAW")) + return -1; + else if (command.Equals("GUESS")) + return -2; + else if (command.Equals("DEFAULT")) + return 0; + else if (char.IsDigit(command[0])) + return int.Parse(command, CultureInfo.InvariantCulture); + else + { + Encoding enc = Encoding.GetEncoding(command); + return enc.CodePage; + } + } + catch (FormatException) + { + Console.Error.WriteLine( + "Invalid format \"{0}\", using machine default", option); + } + catch (ArgumentException) + { + Console.Error.WriteLine( + "Unknown code page \"{0}\", using machine default", option); + } + return 0; + } + } +#region guesser +#if (!BYTEMODE) + // ============================================================== + // ============ Encoding Guesser ============= + // ============================================================== + + /// <summary> + /// This class provides a simple finite state automaton that + /// scans the file looking for (1) valid UTF-8 byte patterns, + /// (2) bytes >= 0x80 which are not part of a UTF-8 sequence. + /// The method then guesses whether it is UTF-8 or maybe some + /// local machine default encoding. This works well for the + /// various Latin encodings. + /// </summary> + internal class Guesser + { + ScanBuff buffer; + + public int GuessCodePage() { return Scan(); } + + const int maxAccept = 10; + const int initial = 0; + const int eofNum = 0; + const int goStart = -1; + const int INITIAL = 0; + const int EndToken = 0; + + #region user code + /* + * Reads the bytes of a file to determine if it is + * UTF-8 or a single-byte code page file. + */ + public long utfX; + public long uppr; + #endregion user code + + int state; + int currentStart = startState[0]; + int code; + + #region ScannerTables + static int[] startState = new int[] { 11, 0 }; + + #region CharacterMap + static sbyte[] map = new sbyte[256] { +/* '\0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x10' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x20' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '@' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 'P' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '`' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 'p' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x80' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\x90' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xA0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xB0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xC0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* '\xD0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* '\xE0' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* '\xF0' */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5 }; + #endregion + + static sbyte[][] nextState = new sbyte[][] { + new sbyte[] {0, 0, 0, 0, 0, 0}, + new sbyte[] {-1, -1, 10, -1, -1, -1}, + new sbyte[] {-1, -1, -1, -1, -1, -1}, + new sbyte[] {-1, -1, 8, -1, -1, -1}, + new sbyte[] {-1, -1, 5, -1, -1, -1}, + new sbyte[] {-1, -1, 6, -1, -1, -1}, + new sbyte[] {-1, -1, 7, -1, -1, -1}, + null, + new sbyte[] {-1, -1, 9, -1, -1, -1}, + null, + null, + new sbyte[] {-1, 1, 2, 3, 4, 2} + }; + + + [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + // Reason for suppression: cannot have self-reference in array initializer. + static Guesser() + { + nextState[7] = nextState[2]; + nextState[9] = nextState[2]; + nextState[10] = nextState[2]; + } + + int NextState() + { + if (code == ScanBuff.EndOfFile) + return eofNum; + else + return nextState[state][map[code]]; + } + #endregion + + public Guesser(System.IO.Stream file) { SetSource(file); } + + public void SetSource(System.IO.Stream source) + { + this.buffer = new BuildBuffer(source); + code = buffer.Read(); + } + + int Scan() + { + for (; ; ) + { + int next; + state = currentStart; + while ((next = NextState()) == goStart) + code = buffer.Read(); + + state = next; + code = buffer.Read(); + + while ((next = NextState()) > eofNum) + { + state = next; + code = buffer.Read(); + } + if (state <= maxAccept) + { + #region ActionSwitch +#pragma warning disable 162 + switch (state) + { + case eofNum: + switch (currentStart) + { + case 11: + if (utfX == 0 && uppr == 0) return -1; /* raw ascii */ + else if (uppr * 10 > utfX) return 0; /* default code page */ + else return 65001; /* UTF-8 encoding */ + break; + } + return EndToken; + case 1: // Recognized '{Upper128}', Shortest string "\xC0" + case 2: // Recognized '{Upper128}', Shortest string "\x80" + case 3: // Recognized '{Upper128}', Shortest string "\xE0" + case 4: // Recognized '{Upper128}', Shortest string "\xF0" + uppr++; + break; + case 5: // Recognized '{Utf8pfx4}{Utf8cont}', Shortest string "\xF0\x80" + uppr += 2; + break; + case 6: // Recognized '{Utf8pfx4}{Utf8cont}{2}', Shortest string "\xF0\x80\x80" + uppr += 3; + break; + case 7: // Recognized '{Utf8pfx4}{Utf8cont}{3}', Shortest string "\xF0\x80\x80\x80" + utfX += 3; + break; + case 8: // Recognized '{Utf8pfx3}{Utf8cont}', Shortest string "\xE0\x80" + uppr += 2; + break; + case 9: // Recognized '{Utf8pfx3}{Utf8cont}{2}', Shortest string "\xE0\x80\x80" + utfX += 2; + break; + case 10: // Recognized '{Utf8pfx2}{Utf8cont}', Shortest string "\xC0\x80" + utfX++; + break; + default: + break; + } +#pragma warning restore 162 + #endregion + } + } + } + } // end class Guesser + +#endif // !BYTEMODE +#endregion + +// End of code copied from embedded resource + +} // end namespace diff --git a/Module5/SimpleLanguage0/SimpleLex.lex b/Module5/SimpleLanguage0/SimpleLex.lex new file mode 100644 index 0000000..10547e9 --- /dev/null +++ b/Module5/SimpleLanguage0/SimpleLex.lex @@ -0,0 +1,74 @@ +%using SimpleParser; +%using QUT.Gppg; +%using System.Linq; + +%namespace SimpleScanner + +Alpha [a-zA-Z_] +Digit [0-9] +AlphaDigit {Alpha}|{Digit} +INTNUM {Digit}+ +REALNUM {INTNUM}\.{INTNUM} +ID {Alpha}{AlphaDigit}* + +%% + +{INTNUM} { + return (int)Tokens.INUM; +} + +{REALNUM} { + return (int)Tokens.RNUM; +} + +{ID} { + int res = ScannerHelper.GetIDToken(yytext); + return res; +} + +":=" { return (int)Tokens.ASSIGN; } +";" { return (int)Tokens.SEMICOLON; } + +[^ \r\n] { + LexError(); + return (int)Tokens.EOF; // конец разбора +} + +%{ + yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); // позиция символа (терминального или нетерминального), возвращаемая @1 @2 и т.д. +%} + +%% + +public override void yyerror(string format, params object[] args) // обработка синтаксических ошибок +{ + var ww = args.Skip(1).Cast<string>().ToArray(); + string errorMsg = string.Format("({0},{1}): Встречено {2}, а ожидалось {3}", yyline, yycol, args[0], string.Join(" или ", ww)); + throw new SyntaxException(errorMsg); +} + +public void LexError() +{ + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); + throw new LexException(errorMsg); +} + +class ScannerHelper +{ + private static Dictionary<string,int> keywords; + + static ScannerHelper() + { + keywords = new Dictionary<string,int>(); + keywords.Add("begin",(int)Tokens.BEGIN); + keywords.Add("end",(int)Tokens.END); + keywords.Add("cycle",(int)Tokens.CYCLE); + } + public static int GetIDToken(string s) + { + if (keywords.ContainsKey(s.ToLower())) // язык нечувствителен к регистру + return keywords[s]; + else + return (int)Tokens.ID; + } +} diff --git a/Module5/SimpleLanguage0/SimpleYacc.cs b/Module5/SimpleLanguage0/SimpleYacc.cs new file mode 100644 index 0000000..d5c2289 --- /dev/null +++ b/Module5/SimpleLanguage0/SimpleYacc.cs @@ -0,0 +1,112 @@ +// This code was generated by the Gardens Point Parser Generator +// Copyright (c) Wayne Kelly, QUT 2005-2010 +// (see accompanying GPPGcopyright.rtf) + +// GPPG version 1.3.6 +// Machine: HUB +// DateTime: 21.09.2017 20:15:14 +// UserName: someone +// Input file <SimpleYacc.y> + +// options: no-lines gplex + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using QUT.Gppg; + +namespace SimpleParser +{ +public enum Tokens { + error=1,EOF=2,BEGIN=3,END=4,CYCLE=5,INUM=6, + RNUM=7,ID=8,ASSIGN=9,SEMICOLON=10}; + +// Abstract base class for GPLEX scanners +public abstract class ScanBase : AbstractScanner<int,LexLocation> { + private LexLocation __yylloc = new LexLocation(); + public override LexLocation yylloc { get { return __yylloc; } set { __yylloc = value; } } + protected virtual bool yywrap() { return true; } +} + +public class Parser: ShiftReduceParser<int, LexLocation> +{ + // Verbatim content from SimpleYacc.y +// Эти объявления добавляются в класс GPPGParser, представляющий собой парсер, генерируемый системой gppg + public Parser(AbstractScanner<int, LexLocation> scanner) : base(scanner) { } + // End verbatim content from SimpleYacc.y + +#pragma warning disable 649 + private static Dictionary<int, string> aliasses; +#pragma warning restore 649 + private static Rule[] rules = new Rule[14]; + private static State[] states = new State[22]; + private static string[] nonTerms = new string[] { + "progr", "$accept", "block", "stlist", "statement", "assign", "cycle", + "ident", "expr", }; + + static Parser() { + states[0] = new State(new int[]{3,4},new int[]{-1,1,-3,3}); + states[1] = new State(new int[]{2,2}); + states[2] = new State(-1); + states[3] = new State(-2); + states[4] = new State(new int[]{8,14,3,4,5,18},new int[]{-4,5,-5,21,-6,9,-8,10,-3,16,-7,17}); + states[5] = new State(new int[]{4,6,10,7}); + states[6] = new State(-12); + states[7] = new State(new int[]{8,14,3,4,5,18},new int[]{-5,8,-6,9,-8,10,-3,16,-7,17}); + states[8] = new State(-4); + states[9] = new State(-5); + states[10] = new State(new int[]{9,11}); + states[11] = new State(new int[]{8,14,6,15},new int[]{-9,12,-8,13}); + states[12] = new State(-9); + states[13] = new State(-10); + states[14] = new State(-8); + states[15] = new State(-11); + states[16] = new State(-6); + states[17] = new State(-7); + states[18] = new State(new int[]{8,14,6,15},new int[]{-9,19,-8,13}); + states[19] = new State(new int[]{8,14,3,4,5,18},new int[]{-5,20,-6,9,-8,10,-3,16,-7,17}); + states[20] = new State(-13); + states[21] = new State(-3); + + rules[1] = new Rule(-2, new int[]{-1,2}); + rules[2] = new Rule(-1, new int[]{-3}); + rules[3] = new Rule(-4, new int[]{-5}); + rules[4] = new Rule(-4, new int[]{-4,10,-5}); + rules[5] = new Rule(-5, new int[]{-6}); + rules[6] = new Rule(-5, new int[]{-3}); + rules[7] = new Rule(-5, new int[]{-7}); + rules[8] = new Rule(-8, new int[]{8}); + rules[9] = new Rule(-6, new int[]{-8,9,-9}); + rules[10] = new Rule(-9, new int[]{-8}); + rules[11] = new Rule(-9, new int[]{6}); + rules[12] = new Rule(-3, new int[]{3,-4,4}); + rules[13] = new Rule(-7, new int[]{5,-9,-5}); + } + + protected override void Initialize() { + this.InitSpecialTokens((int)Tokens.error, (int)Tokens.EOF); + this.InitStates(states); + this.InitRules(rules); + this.InitNonTerminals(nonTerms); + } + + protected override void DoAction(int action) + { + switch (action) + { + } + } + + protected override string TerminalToString(int terminal) + { + if (aliasses != null && aliasses.ContainsKey(terminal)) + return aliasses[terminal]; + else if (((Tokens)terminal).ToString() != terminal.ToString(CultureInfo.InvariantCulture)) + return ((Tokens)terminal).ToString(); + else + return CharToString((char)terminal); + } + +} +} diff --git a/Module5/SimpleLanguage0/SimpleYacc.lst b/Module5/SimpleLanguage0/SimpleYacc.lst new file mode 100644 index 0000000..6a40f2d --- /dev/null +++ b/Module5/SimpleLanguage0/SimpleYacc.lst @@ -0,0 +1,64 @@ + +// ========================================================================== +// GPPG error listing for yacc source file <SimpleYacc.y> +// ========================================================================== +// Version: 1.3.6 +// Machine: SSM +// DateTime: 17.08.2014 10:25:15 +// UserName: Станислав +// ========================================================================== + + +%{ +// ГќГІГЁ îáúÿâëåГГЁГї äîáà âëÿþòñÿ Гў êëà ññ GPPGParser, ïðåäñòà âëÿþùèé ñîáîé ïà ðñåð, ГЈГҐГåðèðóåìûé ñèñòåìîé gppg + public Parser(AbstractScanner<int, LexLocation> scanner) : base(scanner) { } +%} + +%output = SimpleYacc.cs + +%using System.IO; + +%namespace SimpleParser + +%token BEGIN END CYCLE INUM RNUM ID ASSIGN SEMICOLON + +%% +// Error: NonTerminal symbol "st" has no productions +// Warning: Terminating st fixes the following size-2 NonTerminal set + // {cycle, st} +// Error: There are 2 non-terminating NonTerminal Symbols + // {cycle, st} +// ------------------------------------------------------------------ + +progr : block + ; + +stlist : statement + | stlist SEMICOLON statement + ; + +statement: assign + | block + | cycle + ; + +ident : ID + ; + +assign : ident ASSIGN expr + ; + +expr : ident + | INUM + ; + +block : BEGIN stlist END + ; + +cycle : CYCLE expr st + ; + +%% + +// ========================================================================== + diff --git a/Module5/SimpleLanguage0/SimpleYacc.y b/Module5/SimpleLanguage0/SimpleYacc.y new file mode 100644 index 0000000..9594732 --- /dev/null +++ b/Module5/SimpleLanguage0/SimpleYacc.y @@ -0,0 +1,42 @@ +%{ +// Эти объявления добавляются в класс GPPGParser, представляющий собой парсер, генерируемый системой gppg + public Parser(AbstractScanner<int, LexLocation> scanner) : base(scanner) { } +%} + +%output = SimpleYacc.cs + +%namespace SimpleParser + +%token BEGIN END CYCLE INUM RNUM ID ASSIGN SEMICOLON + +%% + +progr : block + ; + +stlist : statement + | stlist SEMICOLON statement + ; + +statement: assign + | block + | cycle + ; + +ident : ID + ; + +assign : ident ASSIGN expr + ; + +expr : ident + | INUM + ; + +block : BEGIN stlist END + ; + +cycle : CYCLE expr statement + ; + +%% diff --git a/Module5/SimpleLanguage0/a.txt b/Module5/SimpleLanguage0/a.txt new file mode 100644 index 0000000..52ea170 --- /dev/null +++ b/Module5/SimpleLanguage0/a.txt @@ -0,0 +1,10 @@ +begin + b := 2; + a := 3; + a := b; + cycle 3 + begin + a := c; + c := 1 + end +end diff --git a/Module5/SimpleLanguage0/generateParserScanner.bat b/Module5/SimpleLanguage0/generateParserScanner.bat new file mode 100644 index 0000000..7ca5476 --- /dev/null +++ b/Module5/SimpleLanguage0/generateParserScanner.bat @@ -0,0 +1,3 @@ +cls +gplex.exe /unicode SimpleLex.lex +gppg.exe /no-lines /gplex SimpleYacc.y diff --git a/Module6/SimpleLanguage1/Main.cs b/Module6/SimpleLanguage1/Main.cs new file mode 100644 index 0000000..01f9c95 --- /dev/null +++ b/Module6/SimpleLanguage1/Main.cs @@ -0,0 +1,50 @@ +п»їusing System; +using System.IO; +using System.Collections.Generic; +using SimpleScanner; +using SimpleParser; + +namespace SimpleCompiler +{ + public class SimpleCompilerMain + { + public static void Main() + { + string FileName = @"..\..\a.txt"; + try + { + string Text = File.ReadAllText(FileName); + + Scanner scanner = new Scanner(); + scanner.SetSource(Text, 0); + + Parser parser = new Parser(scanner); + + var b = parser.Parse(); + if (!b) + Console.WriteLine("Ошибка"); + else + { + Console.WriteLine("Синтаксическое дерево построено"); + //foreach (var st in parser.root.StList) + //Console.WriteLine(st); + } + } + catch (FileNotFoundException) + { + Console.WriteLine("Файл {0} РЅРµ найден", FileName); + } + catch (LexException e) + { + Console.WriteLine("Лексическая ошибка. " + e.Message); + } + catch (SyntaxException e) + { + Console.WriteLine("Синтаксическая ошибка. " + e.Message); + } + + Console.ReadLine(); + } + + } +} diff --git a/Module6/SimpleLanguage1/ParserHelper.cs b/Module6/SimpleLanguage1/ParserHelper.cs new file mode 100644 index 0000000..1e2138c --- /dev/null +++ b/Module6/SimpleLanguage1/ParserHelper.cs @@ -0,0 +1,18 @@ +п»їusing System; + +namespace SimpleParser +{ + public class LexException : Exception + { + public LexException(string msg) : base(msg) { } + } + public class SyntaxException : Exception + { + public SyntaxException(string msg) : base(msg) { } + } + // Класс глобальных описаний Рё статических методов + // для использования различными подсистемами парсера Рё сканера + public static class ParserHelper + { + } +} \ No newline at end of file diff --git a/Module6/SimpleLanguage1/ProgramTree.cs b/Module6/SimpleLanguage1/ProgramTree.cs new file mode 100644 index 0000000..ade12f7 --- /dev/null +++ b/Module6/SimpleLanguage1/ProgramTree.cs @@ -0,0 +1,68 @@ +п»їusing System.Collections.Generic; + +namespace ProgramTree +{ + public enum AssignType { Assign, AssignPlus, AssignMinus, AssignMult, AssignDivide }; + + public class Node // базовый класс для всех узлов + { + } + + public class ExprNode : Node // базовый класс для всех выражений + { + } + + public class IdNode : ExprNode + { + public string Name { get; set; } + public IdNode(string name) { Name = name; } + } + + public class IntNumNode : ExprNode + { + public int Num { get; set; } + public IntNumNode(int num) { Num = num; } + } + + public class StatementNode : Node // базовый класс для всех операторов + { + } + + public class AssignNode : StatementNode + { + public IdNode Id { get; set; } + public ExprNode Expr { get; set; } + public AssignType AssOp { get; set; } + public AssignNode(IdNode id, ExprNode expr, AssignType assop = AssignType.Assign) + { + Id = id; + Expr = expr; + AssOp = assop; + } + } + + public class CycleNode : StatementNode + { + public ExprNode Expr { get; set; } + public StatementNode Stat { get; set; } + public CycleNode(ExprNode expr, StatementNode stat) + { + Expr = expr; + Stat = stat; + } + } + + public class BlockNode : StatementNode + { + public List<StatementNode> StList = new List<StatementNode>(); + public BlockNode(StatementNode stat) + { + Add(stat); + } + public void Add(StatementNode stat) + { + StList.Add(stat); + } + } + +} \ No newline at end of file diff --git a/Module6/SimpleLanguage1/Properties/AssemblyInfo.cs b/Module6/SimpleLanguage1/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..896cc99 --- /dev/null +++ b/Module6/SimpleLanguage1/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +п»їusing System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Управление общими сведениями Рѕ СЃР±РѕСЂРєРµ осуществляется СЃ помощью +// набора атрибутов. Рзмените значения этих атрибутов, чтобы изменить сведения, +// связанные СЃРѕ СЃР±РѕСЂРєРѕР№. +[assembly: AssemblyTitle("SimpleLang")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SimpleLang")] +[assembly: AssemblyCopyright("Copyright В© 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Параметр ComVisible СЃРѕ значением FALSE делает типы РІ СЃР±РѕСЂРєРµ невидимыми +// для COM-компонентов. Если требуется обратиться Рє типу РІ этой СЃР±РѕСЂРєРµ через +// COM, задайте атрибуту ComVisible значение TRUE для этого типа. +[assembly: ComVisible(false)] + +// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM +[assembly: Guid("06dba63f-4805-4cd3-8a93-b329b2c7e37b")] + +// Сведения Рѕ версии СЃР±РѕСЂРєРё состоят РёР· следующих четырех значений: +// +// РћСЃРЅРѕРІРЅРѕР№ номер версии +// Дополнительный номер версии +// Номер построения +// Редакция +// +// Можно задать РІСЃРµ значения или принять номер построения Рё номер редакции РїРѕ умолчанию, +// используя "*", как показано ниже: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Module6/SimpleLanguage1/ShiftReduceParserCode.cs b/Module6/SimpleLanguage1/ShiftReduceParserCode.cs new file mode 100644 index 0000000..c110ba1 --- /dev/null +++ b/Module6/SimpleLanguage1/ShiftReduceParserCode.cs @@ -0,0 +1,944 @@ +// Gardens Point Parser Generator +// Copyright (c) Wayne Kelly, QUT 2005-2009 +// (see accompanying GPPGcopyright.rtf) +#define EXPORT_GPPG + +using System; +using System.Text; +using System.Globalization; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; + +namespace QUT.Gppg +{ + /// <summary> + /// Abstract class for GPPG shift-reduce parsers. + /// Parsers generated by GPPG derive from this base + /// class, overriding the abstract Initialize() and + /// DoAction() methods. + /// </summary> + /// <typeparam name="TValue">Semantic value type</typeparam> + /// <typeparam name="TSpan">Location type</typeparam> +#if EXPORT_GPPG + public abstract class ShiftReduceParser<TValue, TSpan> +#else + internal abstract class ShiftReduceParser<TValue, TSpan> +#endif + where TSpan : IMerge<TSpan>, new() + { + public AbstractScanner<TValue, TSpan> scanner; + /// <summary> + /// The abstract scanner for this parser. + /// </summary> + protected AbstractScanner<TValue, TSpan> Scanner { + get { return scanner; } + set { scanner = value; } + } + + /// <summary> + /// Constructor for base class + /// </summary> + /// <param name="scanner">Scanner instance for this parser</param> + protected ShiftReduceParser(AbstractScanner<TValue, TSpan> scanner) + { + this.scanner = scanner; + } + + // ============================================================== + // TECHNICAL EXPLANATION. + // Why the next two fields are not exposed via properties. + // ============================================================== + // These fields are of the generic parameter types, and are + // frequently instantiated as struct types in derived classes. + // Semantic actions are defined in the derived classes and refer + // to instance fields of these structs. Is such cases the code + // "get_CurrentSemanticValue().myField = blah;" will fail since + // the getter pushes the value of the field, not the reference. + // So, in the presence of properties, gppg would need to encode + // such field accesses as ... + // "tmp = get_CurrentSemanticValue(); // Fetch value + // tmp.myField = blah; // update + // set_CurrentSemanticValue(tmp); " // Write update back. + // There is no issue if TValue is restricted to be a ref type. + // The same explanation applies to scanner.yylval. + // ============================================================== + /// <summary> + /// The current value of the "$$" symbolic variable in the parser + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + protected TValue CurrentSemanticValue; + + /// <summary> + /// The current value of the "@$" symbolic variable in the parser + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + protected TSpan CurrentLocationSpan; + + private TSpan LastSpan; + private int NextToken; + private State FsaState; + private bool recovering; + private int tokensSinceLastError; + + private PushdownPrefixState<State> StateStack = new PushdownPrefixState<State>(); + private PushdownPrefixState<TValue> valueStack = new PushdownPrefixState<TValue>(); + private PushdownPrefixState<TSpan> locationStack = new PushdownPrefixState<TSpan>(); + + /// <summary> + /// The stack of semantic value (YYSTYPE) values. + /// </summary> + protected PushdownPrefixState<TValue> ValueStack { get { return valueStack; } } + + /// <summary> + /// The stack of location value (YYLTYPE) varlues. + /// </summary> + protected PushdownPrefixState<TSpan> LocationStack { get { return locationStack; } } + + private int errorToken; + private int endOfFileToken; + private string[] nonTerminals; + private State[] states; + private Rule[] rules; + + /// <summary> + /// Initialization method to allow derived classes + /// to insert the rule list into this base class. + /// </summary> + /// <param name="rules">The array of Rule objects</param> + protected void InitRules(Rule[] rules) { this.rules = rules; } + + /// <summary> + /// Initialization method to allow derived classes to + /// insert the states table into this base class. + /// </summary> + /// <param name="states">The pre-initialized states table</param> + protected void InitStates(State[] states) { this.states = states; } + + /// <summary> + /// OBSOLETE FOR VERSION 1.4.0 + /// </summary> + /// <param name="size"></param> + protected void InitStateTable(int size) { states = new State[size]; } + + /// <summary> + /// Initialization method to allow derived classes + /// to insert the special value for the error and EOF tokens. + /// </summary> + /// <param name="err">The error state ordinal</param> + /// <param name="end">The EOF stat ordinal</param> + protected void InitSpecialTokens(int err, int end) + { + errorToken = err; + endOfFileToken = end; + } + + /// <summary> + /// Initialization method to allow derived classes to + /// insert the non-terminal symbol names into this base class. + /// </summary> + /// <param name="names">Non-terminal symbol names</param> + protected void InitNonTerminals(string[] names) { nonTerminals = names; } + + #region YYAbort, YYAccept etcetera. + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class AcceptException : Exception + { + internal AcceptException() { } + protected AcceptException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class AbortException : Exception + { + internal AbortException() { } + protected AbortException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class ErrorException : Exception + { + internal ErrorException() { } + protected ErrorException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + + // The following methods are only called from within + // a semantic action. The thrown exceptions can never + // propagate outside the ShiftReduceParser class in + // which they are nested. + + /// <summary> + /// Force parser to terminate, returning "true" + /// </summary> + protected static void YYAccept() { throw new AcceptException(); } + + /// <summary> + /// Force parser to terminate, returning "false" + /// </summary> + protected static void YYAbort() { throw new AbortException(); } + + /// <summary> + /// Force parser to terminate, returning + /// "false" if error recovery fails. + /// </summary> + protected static void YYError() { throw new ErrorException(); } + + /// <summary> + /// Check if parser in error recovery state. + /// </summary> + protected bool YYRecovering { get { return recovering; } } + #endregion + + /// <summary> + /// Abstract base method. ShiftReduceParser calls this + /// to initialize the base class data structures. Concrete + /// parser classes must override this method. + /// </summary> + protected abstract void Initialize(); + + /// <summary> + /// Main entry point of the Shift-Reduce Parser. + /// </summary> + /// <returns>True if parse succeeds, else false for + /// unrecoverable errors</returns> + public bool Parse() + { + Initialize(); // allow derived classes to instantiate rules, states and nonTerminals + + NextToken = 0; + FsaState = states[0]; + + StateStack.Push(FsaState); + valueStack.Push(CurrentSemanticValue); + LocationStack.Push(CurrentLocationSpan); + + while (true) + { +#if TRACE_ACTIONS + Console.Error.WriteLine("Entering state {0} ", FsaState.number); +#endif + int action = FsaState.defaultAction; + + if (FsaState.ParserTable != null) + { + if (NextToken == 0) + { +#if TRACE_ACTIONS + Console.Error.Write("Reading a token: "); +#endif + // We save the last token span, so that the location span + // of production right hand sides that begin or end with a + // nullable production will be correct. + LastSpan = scanner.yylloc; + NextToken = scanner.yylex(); + } + +#if TRACE_ACTIONS + Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken)); +#endif + if (FsaState.ParserTable.ContainsKey(NextToken)) + action = FsaState.ParserTable[NextToken]; + } + + if (action > 0) // shift + { + Shift(action); + } + else if (action < 0) // reduce + { + try + { + Reduce(-action); + if (action == -1) // accept + return true; + } + catch (Exception x) + { + if (x is AbortException) + return false; + else if (x is AcceptException) + return true; + else if (x is ErrorException && !ErrorRecovery()) + return false; + else + throw; // Rethrow x, preserving information. + + } + } + else if (action == 0) // error + if (!ErrorRecovery()) + return false; + } + } + + private void Shift(int stateIndex) + { +#if TRACE_ACTIONS + Console.Error.Write("Shifting token {0}, ", TerminalToString(NextToken)); +#endif + FsaState = states[stateIndex]; + + valueStack.Push(scanner.yylval); + StateStack.Push(FsaState); + LocationStack.Push(scanner.yylloc); + + if (recovering) + { + if (NextToken != errorToken) + tokensSinceLastError++; + + if (tokensSinceLastError > 5) + recovering = false; + } + + if (NextToken != endOfFileToken) + NextToken = 0; + } + + private void Reduce(int ruleNumber) + { +#if TRACE_ACTIONS + DisplayRule(ruleNumber); +#endif + Rule rule = rules[ruleNumber]; + // + // Default actions for unit productions. + // + if (rule.RightHandSide.Length == 1) + { + CurrentSemanticValue = valueStack.TopElement(); // Default action: $$ = $1; + CurrentLocationSpan = LocationStack.TopElement(); // Default action "@$ = @1; + } + else + { + if (rule.RightHandSide.Length == 0) + { + // Create a new blank value. + // Explicit semantic action may mutate this value + CurrentSemanticValue = default(TValue); + // The location span for an empty production will start with the + // beginning of the next lexeme, and end with the finish of the + // previous lexeme. This gives the correct behaviour when this + // nonsense value is used in later Merge operations. + CurrentLocationSpan = (scanner.yylloc != null && LastSpan != null ? + scanner.yylloc.Merge(LastSpan) : + default(TSpan)); + } + else + { + // Default action: $$ = $1; + CurrentSemanticValue = valueStack.TopElement(); + // Default action "@$ = @1.Merge(@N)" for location info. + TSpan at1 = LocationStack[LocationStack.Depth - rule.RightHandSide.Length]; + TSpan atN = LocationStack[LocationStack.Depth - 1]; + CurrentLocationSpan = + ((at1 != null && atN != null) ? at1.Merge(atN) : default(TSpan)); + } + } + + DoAction(ruleNumber); + + for (int i = 0; i < rule.RightHandSide.Length; i++) + { + StateStack.Pop(); + valueStack.Pop(); + LocationStack.Pop(); + } + +#if TRACE_ACTIONS + DisplayStack(); +#endif + FsaState = StateStack.TopElement(); + + if (FsaState.Goto.ContainsKey(rule.LeftHandSide)) + FsaState = states[FsaState.Goto[rule.LeftHandSide]]; + + StateStack.Push(FsaState); + valueStack.Push(CurrentSemanticValue); + LocationStack.Push(CurrentLocationSpan); + } + + /// <summary> + /// Execute the selected action from array. + /// Must be overriden in derived classes. + /// </summary> + /// <param name="actionNumber">Index of the action to perform</param> + protected abstract void DoAction(int actionNumber); + + private bool ErrorRecovery() + { + bool discard; + + if (!recovering) // if not recovering from previous error + ReportError(); + + if (!FindErrorRecoveryState()) + return false; + // + // The interim fix for the "looping in error recovery" + // artifact involved moving the setting of the recovering + // bool until after invalid tokens have been discarded. + // + ShiftErrorToken(); + discard = DiscardInvalidTokens(); + recovering = true; + tokensSinceLastError = 0; + return discard; + } + + private void ReportError1() + { + StringBuilder errorMsg = new StringBuilder(); + errorMsg.AppendFormat("Syntax error, unexpected {0}", TerminalToString(NextToken)); + + if (FsaState.ParserTable.Count < 7) + { + bool first = true; + foreach (int terminal in FsaState.ParserTable.Keys) + { + if (first) + errorMsg.Append(", expecting "); + else + errorMsg.Append(", or "); + + errorMsg.Append(TerminalToString(terminal)); + first = false; + } + } + scanner.yyerror(errorMsg.ToString()); + } + + private void ReportError() + { + object[] args = new object[FsaState.ParserTable.Keys.Count+1]; + args[0] = TerminalToString(NextToken); + int i=1; + foreach (int terminal in FsaState.ParserTable.Keys) + { + args[i] = TerminalToString(terminal); + i++; + } + scanner.yyerror("",args); + } + + private void ShiftErrorToken() + { + int old_next = NextToken; + NextToken = errorToken; + + Shift(FsaState.ParserTable[NextToken]); + +#if TRACE_ACTIONS + Console.Error.WriteLine("Entering state {0} ", FsaState.number); +#endif + NextToken = old_next; + } + + private bool FindErrorRecoveryState() + { + while (true) // pop states until one found that accepts error token + { + if (FsaState.ParserTable != null && + FsaState.ParserTable.ContainsKey(errorToken) && + FsaState.ParserTable[errorToken] > 0) // shift + return true; + +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: popping state {0}", StateStack.Top().number); +#endif + StateStack.Pop(); + valueStack.Pop(); + LocationStack.Pop(); + +#if TRACE_ACTIONS + DisplayStack(); +#endif + if (StateStack.IsEmpty()) + { +#if TRACE_ACTIONS + Console.Error.Write("Aborting: didn't find a state that accepts error token"); +#endif + return false; + } + else + FsaState = StateStack.TopElement(); + } + } + + private bool DiscardInvalidTokens() + { + + int action = FsaState.defaultAction; + + if (FsaState.ParserTable != null) + { + // Discard tokens until find one that works ... + while (true) + { + if (NextToken == 0) + { +#if TRACE_ACTIONS + Console.Error.Write("Reading a token: "); +#endif + NextToken = scanner.yylex(); + } + +#if TRACE_ACTIONS + Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken)); +#endif + if (NextToken == endOfFileToken) + return false; + + if (FsaState.ParserTable.ContainsKey(NextToken)) + action = FsaState.ParserTable[NextToken]; + + if (action != 0) + return true; + else + { +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: Discarding {0}", TerminalToString(NextToken)); +#endif + NextToken = 0; + } + } + } + else if (recovering && tokensSinceLastError == 0) + { + // + // Boolean recovering is not set until after the first + // error token has been shifted. Thus if we get back + // here with recovering set and no tokens read we are + // looping on the same error recovery action. This + // happens if current_state.ParserTable is null because + // the state has an LR(0) reduction, but not all + // lookahead tokens are valid. This only occurs for + // error productions that *end* on "error". + // + // This action discards tokens one at a time until + // the looping stops. Another attack would be to always + // use the LALR(1) table if a production ends on "error" + // +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: panic discard of {0}", TerminalToString(NextToken)); +#endif + if (NextToken == endOfFileToken) + return false; + NextToken = 0; + return true; + } + else + return true; + + } + + /// <summary> + /// Traditional YACC method. Discards the next input token. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyclearin")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyclearin")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + protected void yyclearin() { NextToken = 0; } + + /// <summary> + /// Tradional YACC method. Clear the "recovering" flag. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerrok")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerrok")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + protected void yyerrok() + { + recovering = false; + } + + /// <summary> + /// OBSOLETE FOR VERSION 1.4.0 + /// Method used by derived types to insert new + /// state instances in the "states" array. + /// </summary> + /// <param name="stateNumber">index of the state</param> + /// <param name="state">data for the state</param> + protected void AddState(int stateNumber, State state) + { + states[stateNumber] = state; + state.number = stateNumber; + } + + private void DisplayStack() + { + Console.Error.Write("State now"); + for (int i = 0; i < StateStack.Depth; i++) + Console.Error.Write(" {0}", StateStack[i].number); + Console.Error.WriteLine(); + } + + private void DisplayRule(int ruleNumber) + { + Console.Error.Write("Reducing stack by rule {0}, ", ruleNumber); + DisplayProduction(rules[ruleNumber]); + } + + private void DisplayProduction(Rule rule) + { + if (rule.RightHandSide.Length == 0) + Console.Error.Write("/* empty */ "); + else + foreach (int symbol in rule.RightHandSide) + Console.Error.Write("{0} ", SymbolToString(symbol)); + + Console.Error.WriteLine("-> {0}", SymbolToString(rule.LeftHandSide)); + } + + /// <summary> + /// Abstract state class naming terminal symbols. + /// This is overridden by derived classes with the + /// name (or alias) to be used in error messages. + /// </summary> + /// <param name="terminal">The terminal ordinal</param> + /// <returns></returns> + protected abstract string TerminalToString(int terminal); + + private string SymbolToString(int symbol) + { + if (symbol < 0) + return nonTerminals[-symbol]; + else + return TerminalToString(symbol); + } + + /// <summary> + /// Return text representation of argument character + /// </summary> + /// <param name="input">The character to convert</param> + /// <returns>String representation of the character</returns> + protected static string CharToString(char input) + { + switch (input) + { + case '\a': return @"'\a'"; + case '\b': return @"'\b'"; + case '\f': return @"'\f'"; + case '\n': return @"'\n'"; + case '\r': return @"'\r'"; + case '\t': return @"'\t'"; + case '\v': return @"'\v'"; + case '\0': return @"'\0'"; + default: return string.Format(CultureInfo.InvariantCulture, "'{0}'", input); + } + } + } + + /// <summary> + /// Classes implementing this interface must supply a + /// method that merges two location objects to return + /// a new object of the same type. + /// GPPG-generated parsers have the default location + /// action equivalent to "@$ = @1.Merge(@N);" where N + /// is the right-hand-side length of the production. + /// </summary> + /// <typeparam name="TSpan">The Location type</typeparam> +#if EXPORT_GPPG + public interface IMerge<TSpan> +#else + internal interface IMerge<TSpan> +#endif + { + /// <summary> + /// Interface method that creates a location object from + /// the current and last object. Typically used to create + /// a location object extending from the start of the @1 + /// object to the end of the @N object. + /// </summary> + /// <param name="last">The lexically last object to merge</param> + /// <returns>The merged location object</returns> + TSpan Merge(TSpan last); + } + + /// <summary> + /// This is the default class that carries location + /// information from the scanner to the parser. + /// If you don't declare "%YYLTYPE Foo" the parser + /// will expect to deal with this type. + /// </summary> +#if EXPORT_GPPG + public class LexLocation : IMerge<LexLocation> +#else + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + internal class LexLocation : IMerge<LexLocation> +#endif + { + private int startLine; // start line + private int startColumn; // start column + private int endLine; // end line + private int endColumn; // end column + + /// <summary> + /// The line at which the text span starts. + /// </summary> + public int StartLine { get { return startLine; } } + + /// <summary> + /// The column at which the text span starts. + /// </summary> + public int StartColumn { get { return startColumn; } } + + /// <summary> + /// The line on which the text span ends. + /// </summary> + public int EndLine { get { return endLine; } } + + /// <summary> + /// The column of the first character + /// beyond the end of the text span. + /// </summary> + public int EndColumn { get { return endColumn; } } + + /// <summary> + /// Default no-arg constructor. + /// </summary> + public LexLocation() + { } + + /// <summary> + /// Constructor for text-span with given start and end. + /// </summary> + /// <param name="sl">start line</param> + /// <param name="sc">start column</param> + /// <param name="el">end line </param> + /// <param name="ec">end column</param> + public LexLocation(int sl, int sc, int el, int ec) + { startLine = sl; startColumn = sc; endLine = el; endColumn = ec; } + + /// <summary> + /// Create a text location which spans from the + /// start of "this" to the end of the argument "last" + /// </summary> + /// <param name="last">The last location in the result span</param> + /// <returns>The merged span</returns> + public LexLocation Merge(LexLocation last) + { return new LexLocation(this.startLine, this.startColumn, last.endLine, last.endColumn); } + + } + + /// <summary> + /// Abstract scanner class that GPPG expects its scanners to + /// extend. + /// </summary> + /// <typeparam name="TValue">Semantic value type YYSTYPE</typeparam> + /// <typeparam name="TSpan">Source location type YYLTYPE</typeparam> +#if EXPORT_GPPG + public abstract class AbstractScanner<TValue, TSpan> +#else + internal abstract class AbstractScanner<TValue, TSpan> +#endif + where TSpan : IMerge<TSpan> + { + /// <summary> + /// Lexical value optionally set by the scanner. The value + /// is of the %YYSTYPE type declared in the parser spec. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylval")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylval")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + // A field must be declared for this value of parametric type, + // since it may be instantiated by a value struct. If it were + // implemented as a property, machine generated code in derived + // types would not be able to select on the returned value. + public TValue yylval; // Lexical value: set by scanner + + /// <summary> + /// Current scanner location property. The value is of the + /// type declared by %YYLTYPE in the parser specification. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylloc")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylloc")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public virtual TSpan yylloc + { + get { return default(TSpan); } // Empty implementation allowing + set { /* skip */ } // yylloc to be ignored entirely. + } + + /// <summary> + /// Main call point for LEX-like scanners. Returns an int + /// corresponding to the token recognized by the scanner. + /// </summary> + /// <returns>An int corresponding to the token</returns> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public abstract int yylex(); + + /// <summary> + /// Traditional error reporting provided by LEX-like scanners + /// to their YACC-like clients. + /// </summary> + /// <param name="format">Message format string</param> + /// <param name="args">Optional array of args</param> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerror")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerror")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public virtual void yyerror(string format, params object[] args) { } + } + + /// <summary> + /// Encapsulated state for the parser. + /// Opaque to users, visible to the tool-generated code. + /// </summary> +#if EXPORT_GPPG + public class State +#else + internal class State +#endif + { + internal int number; + internal Dictionary<int, int> ParserTable; // Terminal -> ParseAction + internal Dictionary<int, int> Goto; // NonTerminal -> State; + internal int defaultAction; // = 0; // ParseAction + + /// <summary> + /// State transition data for this state. Pairs of elements of the + /// goto array associate symbol ordinals with next state indices. + /// The actions array is passed to another constructor. + /// </summary> + /// <param name="actions">The action list</param> + /// <param name="goToList">Next state data</param> + public State(int[] actions, int[] goToList) + : this(actions) + { + Goto = new Dictionary<int, int>(); + for (int i = 0; i < goToList.Length; i += 2) + Goto.Add(goToList[i], goToList[i + 1]); + } + + /// <summary> + /// Action data for this state. Pairs of elements of the + /// action array associate action ordinals with each of + /// those symbols that have actions in the current state. + /// </summary> + /// <param name="actions">The action array</param> + public State(int[] actions) + { + ParserTable = new Dictionary<int, int>(); + for (int i = 0; i < actions.Length; i += 2) + ParserTable.Add(actions[i], actions[i + 1]); + } + + /// <summary> + /// Set the default action for this state. + /// </summary> + /// <param name="defaultAction">Ordinal of the default action</param> + public State(int defaultAction) + { + this.defaultAction = defaultAction; + } + + /// <summary> + /// Set the default action and the state transition table. + /// </summary> + /// <param name="defaultAction">The default action</param> + /// <param name="goToList">Transitions from this state</param> + public State(int defaultAction, int[] goToList) + : this(defaultAction) + { + Goto = new Dictionary<int, int>(); + for (int i = 0; i < goToList.Length; i += 2) + Goto.Add(goToList[i], goToList[i + 1]); + } + } + + /// <summary> + /// Rule representation at runtime. + /// </summary> +#if EXPORT_GPPG + public class Rule +#else + internal class Rule +#endif + { + internal int LeftHandSide; // symbol + internal int[] RightHandSide; // symbols + + /// <summary> + /// Rule constructor. This holds the ordinal of + /// the left hand side symbol, and the list of + /// right hand side symbols, in lexical order. + /// </summary> + /// <param name="left">The LHS non-terminal</param> + /// <param name="right">The RHS symbols, in lexical order</param> + public Rule(int left, int[] right) + { + this.LeftHandSide = left; + this.RightHandSide = right; + } + } + + /// <summary> + /// Stack utility for the shift-reduce parser. + /// GPPG parsers have three instances: + /// (1) The parser state stack, T = QUT.Gppg.State, + /// (2) The semantic value stack, T = TValue, + /// (3) The location stack, T = TSpan. + /// </summary> + /// <typeparam name="T"></typeparam> +#if EXPORT_GPPG + public class PushdownPrefixState<T> +#else + internal class PushdownPrefixState<T> +#endif + { + // Note that we cannot use the BCL Stack<T> class + // here as derived types need to index into stacks. + // + private T[] array = new T[8]; + private int tos = 0; + + /// <summary> + /// Indexer for values of the stack below the top. + /// </summary> + /// <param name="index">index of the element, starting from the bottom</param> + /// <returns>the selected element</returns> + public T this[int index] { get { return array[index]; } } + + /// <summary> + /// The current depth of the stack. + /// </summary> + public int Depth { get { return tos; } } + + internal void Push(T value) + { + if (tos >= array.Length) + { + T[] newarray = new T[array.Length * 2]; + System.Array.Copy(array, newarray, tos); + array = newarray; + } + array[tos++] = value; + } + + internal T Pop() + { + T rslt = array[--tos]; + array[tos] = default(T); + return rslt; + } + + internal T TopElement() { return array[tos - 1]; } + + internal bool IsEmpty() { return tos == 0; } + } +} \ No newline at end of file diff --git a/Module6/SimpleLanguage1/SimpleLang1.csproj b/Module6/SimpleLanguage1/SimpleLang1.csproj new file mode 100644 index 0000000..9443c7d --- /dev/null +++ b/Module6/SimpleLanguage1/SimpleLang1.csproj @@ -0,0 +1,62 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>SimpleLang</RootNamespace> + <AssemblyName>SimpleLang</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Main.cs" /> + <Compile Include="ParserHelper.cs" /> + <Compile Include="ProgramTree.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="ShiftReduceParserCode.cs" /> + <Compile Include="SimpleLex.cs" /> + <Compile Include="SimpleYacc.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project> \ No newline at end of file diff --git a/Module6/SimpleLanguage1/SimpleLang1.sln b/Module6/SimpleLanguage1/SimpleLang1.sln new file mode 100644 index 0000000..adda773 --- /dev/null +++ b/Module6/SimpleLanguage1/SimpleLang1.sln @@ -0,0 +1,22 @@ +п»ї +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleLang1", "SimpleLang1.csproj", "{12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Debug|x86.ActiveCfg = Debug|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Debug|x86.Build.0 = Debug|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Release|x86.ActiveCfg = Release|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Module6/SimpleLanguage1/SimpleLex.cs b/Module6/SimpleLanguage1/SimpleLex.cs new file mode 100644 index 0000000..ceaf75d --- /dev/null +++ b/Module6/SimpleLanguage1/SimpleLex.cs @@ -0,0 +1,1489 @@ +// +// This CSharp output file generated by Gardens Point LEX +// Version: 1.1.3.301 +// Machine: HUB +// DateTime: 21.09.2017 20:37:24 +// UserName: someone +// GPLEX input file <SimpleLex.lex> +// GPLEX frame file <embedded resource> +// +// Option settings: unicode, parser, minimize +// Option settings: classes, compressMap, compressNext, persistBuffer, embedbuffers +// Fallback code page: Target machine default +// + +// +// Experimental embedded frame +// Version 1.1.3 of 18-April-2010 +// +// +#define BACKUP +#define PERSIST + +using System; +using System.IO; +using System.Text; +using System.Globalization; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; + +using SimpleParser; +using QUT.Gppg; +using System.Linq; + +namespace SimpleScanner +{ + /// <summary> + /// Summary Canonical example of GPLEX automaton + /// </summary> + +#if STANDALONE + // + // These are the dummy declarations for stand-alone GPLEX applications + // normally these declarations would come from the parser. + // If you declare /noparser, or %option noparser then you get this. + // + + public enum Tokens + { + EOF = 0, maxParseToken = int.MaxValue + // must have at least these two, values are almost arbitrary + } + + public abstract class ScanBase + { + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + public abstract int yylex(); + + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yywrap")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yywrap")] + protected virtual bool yywrap() { return true; } + +#if BABEL + protected abstract int CurrentSc { get; set; } + // EolState is the 32-bit of state data persisted at + // the end of each line for Visual Studio colorization. + // The default is to return CurrentSc. You must override + // this if you want more complicated behavior. + public virtual int EolState { + get { return CurrentSc; } + set { CurrentSc = value; } + } + } + + public interface IColorScan + { + void SetSource(string source, int offset); + int GetNext(ref int state, out int start, out int end); +#endif // BABEL + } + +#endif // STANDALONE + + // If the compiler can't find the scanner base class maybe you + // need to run GPPG with the /gplex option, or GPLEX with /noparser +#if BABEL + public sealed partial class Scanner : ScanBase, IColorScan + { + private ScanBuff buffer; + int currentScOrd; // start condition ordinal + + protected override int CurrentSc + { + // The current start state is a property + // to try to avoid the user error of setting + // scState but forgetting to update the FSA + // start state "currentStart" + // + get { return currentScOrd; } // i.e. return YY_START; + set { currentScOrd = value; // i.e. BEGIN(value); + currentStart = startState[value]; } + } +#else // BABEL + public sealed partial class Scanner : ScanBase + { + private ScanBuff buffer; + int currentScOrd; // start condition ordinal +#endif // BABEL + + /// <summary> + /// The input buffer for this scanner. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public ScanBuff Buffer { get { return buffer; } } + + private static int GetMaxParseToken() { + System.Reflection.FieldInfo f = typeof(Tokens).GetField("maxParseToken"); + return (f == null ? int.MaxValue : (int)f.GetValue(null)); + } + + static int parserMax = GetMaxParseToken(); + + enum Result {accept, noMatch, contextFound}; + + const int maxAccept = 7; + const int initial = 8; + const int eofNum = 0; + const int goStart = -1; + const int INITIAL = 0; + +#region user code +#endregion user code + + int state; + int currentStart = startState[0]; + int code; // last code read + int cCol; // column number of code + int lNum; // current line number + // + // The following instance variables are used, among other + // things, for constructing the yylloc location objects. + // + int tokPos; // buffer position at start of token + int tokCol; // zero-based column number at start of token + int tokLin; // line number at start of token + int tokEPos; // buffer position at end of token + int tokECol; // column number at end of token + int tokELin; // line number at end of token + string tokTxt; // lazily constructed text of token +#if STACK + private Stack<int> scStack = new Stack<int>(); +#endif // STACK + +#region ScannerTables + struct Table { + public int min; public int rng; public int dflt; + public sbyte[] nxt; + public Table(int m, int x, int d, sbyte[] n) { + min = m; rng = x; dflt = d; nxt = n; + } + }; + + static int[] startState = new int[] {8, 0}; + +#region CompressedCharacterMap + // + // There are 8 equivalence classes + // There are 2 character sequence regions + // There are 1 tables, 123 entries + // There are 1 runs, 0 singletons + // Decision tree depth is 1 + // + static sbyte[] mapC0 = new sbyte[123] { +/* '\0' */ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 0, 7, 7, +/* '\x10' */ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +/* '\x20' */ 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, +/* '0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 6, 7, 5, 7, 7, +/* '@' */ 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* 'P' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 3, +/* '`' */ 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* 'p' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; + + static sbyte MapC(int code) + { // '\0' <= code <= '\U0010FFFF' + if (code < 123) // '\0' <= code <= 'z' + return mapC0[code - 0]; + else // '{' <= code <= '\U0010FFFF' + return (sbyte)7; + } +#endregion + + static Table[] NxS = new Table[10] { +/* NxS[ 0] */ new Table(0, 0, 0, null), +/* NxS[ 1] */ new Table(1, 2, -1, new sbyte[] {1, 9}), +/* NxS[ 2] */ new Table(0, 0, -1, null), +/* NxS[ 3] */ new Table(1, 3, -1, new sbyte[] {3, -1, 3}), +/* NxS[ 4] */ new Table(5, 1, -1, new sbyte[] {6}), +/* NxS[ 5] */ new Table(0, 0, -1, null), +/* NxS[ 6] */ new Table(0, 0, -1, null), +/* NxS[ 7] */ new Table(1, 1, -1, new sbyte[] {7}), +/* NxS[ 8] */ new Table(1, 7, -1, new sbyte[] {1, 2, 3, 4, 2, 5, + 2}), +/* NxS[ 9] */ new Table(1, 1, -1, new sbyte[] {7}), + }; + +int NextState() { + if (code == ScanBuff.EndOfFile) + return eofNum; + else + unchecked { + int rslt; + int idx = MapC(code) - NxS[state].min; + if (idx < 0) idx += 8; + if ((uint)idx >= (uint)NxS[state].rng) rslt = NxS[state].dflt; + else rslt = NxS[state].nxt[idx]; + return rslt; + } +} + +#endregion + + +#if BACKUP + // ============================================================== + // == Nested struct used for backup in automata that do backup == + // ============================================================== + + struct Context // class used for automaton backup. + { + public int bPos; + public int rPos; // scanner.readPos saved value + public int cCol; + public int lNum; // Need this in case of backup over EOL. + public int state; + public int cChr; + } + + private Context ctx = new Context(); +#endif // BACKUP + + // ============================================================== + // ==== Nested struct to support input switching in scanners ==== + // ============================================================== + + struct BufferContext { + internal ScanBuff buffSv; + internal int chrSv; + internal int cColSv; + internal int lNumSv; + } + + // ============================================================== + // ===== Private methods to save and restore buffer contexts ==== + // ============================================================== + + /// <summary> + /// This method creates a buffer context record from + /// the current buffer object, together with some + /// scanner state values. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + BufferContext MkBuffCtx() + { + BufferContext rslt; + rslt.buffSv = this.buffer; + rslt.chrSv = this.code; + rslt.cColSv = this.cCol; + rslt.lNumSv = this.lNum; + return rslt; + } + + /// <summary> + /// This method restores the buffer value and allied + /// scanner state from the given context record value. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void RestoreBuffCtx(BufferContext value) + { + this.buffer = value.buffSv; + this.code = value.chrSv; + this.cCol = value.cColSv; + this.lNum = value.lNumSv; + } + // =================== End Nested classes ======================= + +#if !NOFILES + public Scanner(Stream file) { + SetSource(file, 0); // unicode option + } + + public Scanner(Stream file, string codepage) { + SetSource(file, CodePageHandling.GetCodePage(codepage)); + } + +#endif // !NOFILES + + public Scanner() { } + + private int readPos; + + void GetCode() + { + if (code == '\n') // This needs to be fixed for other conventions + // i.e. [\r\n\205\u2028\u2029] + { + cCol = -1; + lNum++; + } + readPos = buffer.Pos; + + // Now read new codepoint. + code = buffer.Read(); + if (code > ScanBuff.EndOfFile) + { +#if (!BYTEMODE) + if (code >= 0xD800 && code <= 0xDBFF) + { + int next = buffer.Read(); + if (next < 0xDC00 || next > 0xDFFF) + code = ScanBuff.UnicodeReplacementChar; + else + code = (0x10000 + (code & 0x3FF << 10) + (next & 0x3FF)); + } +#endif + cCol++; + } + } + + void MarkToken() + { +#if (!PERSIST) + buffer.Mark(); +#endif + tokPos = readPos; + tokLin = lNum; + tokCol = cCol; + } + + void MarkEnd() + { + tokTxt = null; + tokEPos = readPos; + tokELin = lNum; + tokECol = cCol; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int Peek() + { + int rslt, codeSv = code, cColSv = cCol, lNumSv = lNum, bPosSv = buffer.Pos; + GetCode(); rslt = code; + lNum = lNumSv; cCol = cColSv; code = codeSv; buffer.Pos = bPosSv; + return rslt; + } + + // ============================================================== + // ===== Initialization of string-based input buffers ==== + // ============================================================== + + /// <summary> + /// Create and initialize a StringBuff buffer object for this scanner + /// </summary> + /// <param name="source">the input string</param> + /// <param name="offset">starting offset in the string</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(string source, int offset) + { + this.buffer = ScanBuff.GetBuffer(source); + this.buffer.Pos = offset; + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } + +#if !NOFILES + // ================ LineBuffer Initialization =================== + + /// <summary> + /// Create and initialize a LineBuff buffer object for this scanner + /// </summary> + /// <param name="source">the list of input strings</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(IList<string> source) + { + this.buffer = ScanBuff.GetBuffer(source); + this.code = '\n'; // to initialize yyline, yycol and lineStart + this.lNum = 0; + GetCode(); + } + + // =============== StreamBuffer Initialization ================== + + /// <summary> + /// Create and initialize a StreamBuff buffer object for this scanner. + /// StreamBuff is buffer for 8-bit byte files. + /// </summary> + /// <param name="source">the input byte stream</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(Stream source) + { + this.buffer = ScanBuff.GetBuffer(source); + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } + +#if !BYTEMODE + // ================ TextBuffer Initialization =================== + + /// <summary> + /// Create and initialize a TextBuff buffer object for this scanner. + /// TextBuff is a buffer for encoded unicode files. + /// </summary> + /// <param name="source">the input text file</param> + /// <param name="fallbackCodePage">Code page to use if file has + /// no BOM. For 0, use machine default; for -1, 8-bit binary</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(Stream source, int fallbackCodePage) + { + this.buffer = ScanBuff.GetBuffer(source, fallbackCodePage); + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } +#endif // !BYTEMODE +#endif // !NOFILES + + // ============================================================== + +#if BABEL + // + // Get the next token for Visual Studio + // + // "state" is the inout mode variable that maintains scanner + // state between calls, using the EolState property. In principle, + // if the calls of EolState are costly set could be called once + // only per line, at the start; and get called only at the end + // of the line. This needs more infrastructure ... + // + public int GetNext(ref int state, out int start, out int end) + { + Tokens next; + int s, e; + s = state; // state at start + EolState = state; + next = (Tokens)Scan(); + state = EolState; + e = state; // state at end; + start = tokPos; + end = tokEPos - 1; // end is the index of last char. + return (int)next; + } +#endif // BABEL + + // ======== AbstractScanner<> Implementation ========= + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + public override int yylex() + { + // parserMax is set by reflecting on the Tokens + // enumeration. If maxParseToken is defined + // that is used, otherwise int.MaxValue is used. + int next; + do { next = Scan(); } while (next >= parserMax); + return next; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yypos { get { return tokPos; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yyline { get { return tokLin; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yycol { get { return tokCol; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yytext")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yytext")] + public string yytext + { + get + { + if (tokTxt == null) + tokTxt = buffer.GetString(tokPos, tokEPos); + return tokTxt; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void yyless(int n) + { + buffer.Pos = tokPos; + // Must read at least one char, so set before start. + cCol = tokCol - 1; + GetCode(); + // Now ensure that line counting is correct. + lNum = tokLin; + // And count the rest of the text. + for (int i = 0; i < n; i++) GetCode(); + MarkEnd(); + } + + // + // It would be nice to count backward in the text + // but it does not seem possible to re-establish + // the correct column counts except by going forward. + // + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void _yytrunc(int n) { yyless(yyleng - n); } + + // + // This is painful, but we no longer count + // codepoints. For the overwhelming majority + // of cases the single line code is fast, for + // the others, well, at least it is all in the + // buffer so no files are touched. Note that we + // can't use (tokEPos - tokPos) because of the + // possibility of surrogate pairs in the token. + // + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyleng")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyleng")] + public int yyleng + { + get { +#if BYTEMODE + return tokEPos - tokPos; +#else + if (tokELin == tokLin) + return tokECol - tokCol; + else { + int ch; + int count = 0; + int save = buffer.Pos; + buffer.Pos = tokPos; + do { + ch = buffer.Read(); + if (!char.IsHighSurrogate((char)ch)) count++; + } while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile); + buffer.Pos = save; + return count; + } +#endif // BYTEMODE + } + } + + // ============ methods available in actions ============== + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal int YY_START { + get { return currentScOrd; } + set { currentScOrd = value; + currentStart = startState[value]; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void BEGIN(int next) { + currentScOrd = next; + currentStart = startState[next]; + } + + // ============== The main tokenizer code ================= + + int Scan() + { + try { + for (; ; ) + { + int next; // next state to enter +#if BACKUP + Result rslt = Result.noMatch; +#endif // BACKUP +#if LEFTANCHORS + for (;;) + { + // Discard characters that do not start any pattern. + // Must check the left anchor condition after *every* GetCode! + state = ((cCol == 0) ? anchorState[currentScOrd] : currentStart); + if ((next = NextState()) != goStart) + break; // LOOP EXIT HERE... + GetCode(); + } + +#else // !LEFTANCHORS + state = currentStart; + while ((next = NextState()) == goStart) + // At this point, the current character has no + // transition from the current state. We discard + // the "no-match" char. In traditional LEX such + // characters are echoed to the console. + GetCode(); +#endif // LEFTANCHORS + // At last, a valid transition ... + MarkToken(); + state = next; + GetCode(); + + while ((next = NextState()) > eofNum) // Exit for goStart AND for eofNum +#if BACKUP + if (state <= maxAccept && next > maxAccept) // need to prepare backup data + { + // ctx is an object. The fields may be + // mutated by the call to Recurse2. + // On return the data in ctx is the + // *latest* accept state that was found. + + rslt = Recurse2(ref ctx, next); + if (rslt == Result.noMatch) + RestoreStateAndPos(ref ctx); + break; + } + else +#endif // BACKUP + { + state = next; + GetCode(); + } + if (state <= maxAccept) + { + MarkEnd(); +#region ActionSwitch +#pragma warning disable 162 + switch (state) + { + case eofNum: + if (yywrap()) + return (int)Tokens.EOF; + break; + case 1: +yylval.iVal = int.Parse(yytext); + return (int)Tokens.INUM; + break; + case 2: + case 4: +LexError(); + break; + case 3: +int res = ScannerHelper.GetIDToken(yytext); + if (res == (int)Tokens.ID) + yylval.sVal = yytext; + return res; + break; + case 5: +return (int)Tokens.SEMICOLON; + break; + case 6: +return (int)Tokens.ASSIGN; + break; + case 7: +yylval.dVal = double.Parse(yytext); + return (int)Tokens.RNUM; + break; + default: + break; + } +#pragma warning restore 162 +#endregion + } + } + } // end try + finally { +// User-specified epilog to scan() +yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); +// End, user-specified epilog + } // end finally + } + +#if BACKUP + Result Recurse2(ref Context ctx, int next) + { + // Assert: at entry "state" is an accept state AND + // NextState(state, code) != goStart AND + // NextState(state, code) is not an accept state. + // + SaveStateAndPos(ref ctx); + state = next; + GetCode(); + + while ((next = NextState()) > eofNum) + { + if (state <= maxAccept && next > maxAccept) // need to update backup data + SaveStateAndPos(ref ctx); + state = next; + if (state == eofNum) return Result.accept; + GetCode(); + } + return (state <= maxAccept ? Result.accept : Result.noMatch); + } + + void SaveStateAndPos(ref Context ctx) + { + ctx.bPos = buffer.Pos; + ctx.rPos = readPos; + ctx.cCol = cCol; + ctx.lNum = lNum; + ctx.state = state; + ctx.cChr = code; + } + + void RestoreStateAndPos(ref Context ctx) + { + buffer.Pos = ctx.bPos; + readPos = ctx.rPos; + cCol = ctx.cCol; + lNum = ctx.lNum; + state = ctx.state; + code = ctx.cChr; + } + +#endif // BACKUP + + // ============= End of the tokenizer code ================ + +#if STACK + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void yy_clear_stack() { scStack.Clear(); } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal int yy_top_state() { return scStack.Peek(); } + + internal void yy_push_state(int state) + { + scStack.Push(currentScOrd); + BEGIN(state); + } + + internal void yy_pop_state() + { + // Protect against input errors that pop too far ... + if (scStack.Count > 0) { + int newSc = scStack.Pop(); + BEGIN(newSc); + } // Otherwise leave stack unchanged. + } + #endif // STACK + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void ECHO() { Console.Out.Write(yytext); } + +#region UserCodeSection + +public override void yyerror(string format, params object[] args) // обработка синтаксических ошибок +{ + var ww = args.Skip(1).Cast<string>().ToArray(); + string errorMsg = string.Format("({0},{1}): Встречено {2}, а ожидалось {3}", yyline, yycol, args[0], string.Join(" или ", ww)); + throw new SyntaxException(errorMsg); +} + +public void LexError() +{ + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); + throw new LexException(errorMsg); +} + +class ScannerHelper +{ + private static Dictionary<string,int> keywords; + + static ScannerHelper() + { + keywords = new Dictionary<string,int>(); + keywords.Add("begin",(int)Tokens.BEGIN); + keywords.Add("end",(int)Tokens.END); + keywords.Add("cycle",(int)Tokens.CYCLE); + } + public static int GetIDToken(string s) + { + if (keywords.ContainsKey(s.ToLower())) + return keywords[s]; + else + return (int)Tokens.ID; + } + +} + +#endregion + } // end class $Scanner + +// ============================================================== +// <auto-generated> +// This code automatically produced from an embedded resource. +// Do not edit this file, or it will become incompatible with +// the specification from which it was generated. +// </auto-generated> +// ============================================================== + +// Code copied from GPLEX embedded resource + [Serializable] + public class BufferException : Exception + { + public BufferException() { } + public BufferException(string message) : base(message) { } + public BufferException(string message, Exception innerException) + : base(message, innerException) { } + protected BufferException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + } + + public abstract class ScanBuff + { + private string fileNm; + + public const int EndOfFile = -1; + public const int UnicodeReplacementChar = 0xFFFD; + + public bool IsFile { get { return (fileNm != null); } } + public string FileName { get { return fileNm; } set { fileNm = value; } } + + public abstract int Pos { get; set; } + public abstract int Read(); + public virtual void Mark() { } + + public abstract string GetString(int begin, int limit); + + public static ScanBuff GetBuffer(string source) + { + return new StringBuffer(source); + } + + public static ScanBuff GetBuffer(IList<string> source) + { + return new LineBuffer(source); + } + + public static ScanBuff GetBuffer(Stream source) + { + return new BuildBuffer(source); + } + +#if (!BYTEMODE) + public static ScanBuff GetBuffer(Stream source, int fallbackCodePage) + { + return new BuildBuffer(source, fallbackCodePage); + } +#endif + } + + #region Buffer classes + + // ============================================================== + // ===== Definitions for various ScanBuff derived classes ==== + // ============================================================== + // =============== String input ================ + // ============================================================== + + /// <summary> + /// This class reads characters from a single string as + /// required, for example, by Visual Studio language services + /// </summary> + sealed class StringBuffer : ScanBuff + { + string str; // input buffer + int bPos; // current position in buffer + int sLen; + + public StringBuffer(string source) + { + this.str = source; + this.sLen = source.Length; + this.FileName = null; + } + + public override int Read() + { + if (bPos < sLen) return str[bPos++]; + else if (bPos == sLen) { bPos++; return '\n'; } // one strike, see new line + else { bPos++; return EndOfFile; } // two strikes and you're out! + } + + public override string GetString(int begin, int limit) + { + // "limit" can be greater than sLen with the BABEL + // option set. Read returns a "virtual" EOL if + // an attempt is made to read past the end of the + // string buffer. Without the guard any attempt + // to fetch yytext for a token that includes the + // EOL will throw an index exception. + if (limit > sLen) limit = sLen; + if (limit <= begin) return ""; + else return str.Substring(begin, limit - begin); + } + + public override int Pos + { + get { return bPos; } + set { bPos = value; } + } + + public override string ToString() { return "StringBuffer"; } + } + + // ============================================================== + // The LineBuff class contributed by Nigel Horspool, + // nigelh@cs.uvic.cs + // ============================================================== + + sealed class LineBuffer : ScanBuff + { + IList<string> line; // list of source lines from a file + int numLines; // number of strings in line list + string curLine; // current line in that list + int cLine; // index of current line in the list + int curLen; // length of current line + int curLineStart; // position of line start in whole file + int curLineEnd; // position of line end in whole file + int maxPos; // max position ever visited in whole file + int cPos; // ordinal number of code in source + + // Constructed from a list of strings, one per source line. + // The lines have had trailing '\n' characters removed. + public LineBuffer(IList<string> lineList) + { + line = lineList; + numLines = line.Count; + cPos = curLineStart = 0; + curLine = (numLines > 0 ? line[0] : ""); + maxPos = curLineEnd = curLen = curLine.Length; + cLine = 1; + FileName = null; + } + + public override int Read() + { + if (cPos < curLineEnd) + return curLine[cPos++ - curLineStart]; + if (cPos++ == curLineEnd) + return '\n'; + if (cLine >= numLines) + return EndOfFile; + curLine = line[cLine]; + curLen = curLine.Length; + curLineStart = curLineEnd + 1; + curLineEnd = curLineStart + curLen; + if (curLineEnd > maxPos) + maxPos = curLineEnd; + cLine++; + return curLen > 0 ? curLine[0] : '\n'; + } + + // To speed up searches for the line containing a position + private int cachedPosition; + private int cachedIxdex; + private int cachedLineStart; + + // Given a position pos within the entire source, the results are + // ix -- the index of the containing line + // lstart -- the position of the first character on that line + private void findIndex(int pos, out int ix, out int lstart) + { + if (pos >= cachedPosition) + { + ix = cachedIxdex; lstart = cachedLineStart; + } + else + { + ix = lstart = 0; + } + for (; ; ) + { + int len = line[ix].Length + 1; + if (pos < lstart + len) break; + lstart += len; + ix++; + } + cachedPosition = pos; + cachedIxdex = ix; + cachedLineStart = lstart; + } + + public override string GetString(int begin, int limit) + { + if (begin >= maxPos || limit <= begin) return ""; + int endIx, begIx, endLineStart, begLineStart; + findIndex(begin, out begIx, out begLineStart); + int begCol = begin - begLineStart; + findIndex(limit, out endIx, out endLineStart); + int endCol = limit - endLineStart; + string s = line[begIx]; + if (begIx == endIx) + { + // the usual case, substring all on one line + return (endCol <= s.Length) ? + s.Substring(begCol, endCol - begCol) + : s.Substring(begCol) + "\n"; + } + // the string spans multiple lines, yuk! + StringBuilder sb = new StringBuilder(); + if (begCol < s.Length) + sb.Append(s.Substring(begCol)); + for (; ; ) + { + sb.Append("\n"); + s = line[++begIx]; + if (begIx >= endIx) break; + sb.Append(s); + } + if (endCol <= s.Length) + { + sb.Append(s.Substring(0, endCol)); + } + else + { + sb.Append(s); + sb.Append("\n"); + } + return sb.ToString(); + } + + public override int Pos + { + get { return cPos; } + set + { + cPos = value; + findIndex(cPos, out cLine, out curLineStart); + curLine = line[cLine]; + curLineEnd = curLineStart + curLine.Length; + } + } + + public override string ToString() { return "LineBuffer"; } + } + + + // ============================================================== + // ===== class BuildBuff : for unicode text files ======== + // ============================================================== + + class BuildBuffer : ScanBuff + { + // Double buffer for char stream. + class BufferElement + { + StringBuilder bldr = new StringBuilder(); + StringBuilder next = new StringBuilder(); + int minIx; + int maxIx; + int brkIx; + bool appendToNext; + + internal BufferElement() { } + + internal int MaxIndex { get { return maxIx; } } + // internal int MinIndex { get { return minIx; } } + + internal char this[int index] + { + get + { + if (index < minIx || index >= maxIx) + throw new BufferException("Index was outside data buffer"); + else if (index < brkIx) + return bldr[index - minIx]; + else + return next[index - brkIx]; + } + } + + internal void Append(char[] block, int count) + { + maxIx += count; + if (appendToNext) + this.next.Append(block, 0, count); + else + { + this.bldr.Append(block, 0, count); + brkIx = maxIx; + appendToNext = true; + } + } + + internal string GetString(int start, int limit) + { + if (limit <= start) + return ""; + if (start >= minIx && limit <= maxIx) + if (limit < brkIx) // String entirely in bldr builder + return bldr.ToString(start - minIx, limit - start); + else if (start >= brkIx) // String entirely in next builder + return next.ToString(start - brkIx, limit - start); + else // Must do a string-concatenation + return + bldr.ToString(start - minIx, brkIx - start) + + next.ToString(0, limit - brkIx); + else + throw new BufferException("String was outside data buffer"); + } + + internal void Mark(int limit) + { + if (limit > brkIx + 16) // Rotate blocks + { + StringBuilder temp = bldr; + bldr = next; + next = temp; + next.Length = 0; + minIx = brkIx; + brkIx = maxIx; + } + } + } + + BufferElement data = new BufferElement(); + + int bPos; // Postion index in the StringBuilder + BlockReader NextBlk; // Delegate that serves char-arrays; + + private string EncodingName + { + get + { + StreamReader rdr = NextBlk.Target as StreamReader; + return (rdr == null ? "raw-bytes" : rdr.CurrentEncoding.BodyName); + } + } + + public BuildBuffer(Stream stream) + { + FileStream fStrm = (stream as FileStream); + if (fStrm != null) FileName = fStrm.Name; + NextBlk = BlockReaderFactory.Raw(stream); + } + +#if (!BYTEMODE) + public BuildBuffer(Stream stream, int fallbackCodePage) + { + FileStream fStrm = (stream as FileStream); + if (fStrm != null) FileName = fStrm.Name; + NextBlk = BlockReaderFactory.Get(stream, fallbackCodePage); + } +#endif + + /// <summary> + /// Marks a conservative lower bound for the buffer, + /// allowing space to be reclaimed. If an application + /// needs to call GetString at arbitrary past locations + /// in the input stream, Mark() is not called. + /// </summary> + public override void Mark() { data.Mark(bPos - 2); } + + public override int Pos + { + get { return bPos; } + set { bPos = value; } + } + + + /// <summary> + /// Read returns the ordinal number of the next char, or + /// EOF (-1) for an end of stream. Note that the next + /// code point may require *two* calls of Read(). + /// </summary> + /// <returns></returns> + public override int Read() + { + // + // Characters at positions + // [data.offset, data.offset + data.bldr.Length) + // are available in data.bldr. + // + if (bPos < data.MaxIndex) + { + // ch0 cannot be EOF + return (int)data[bPos++]; + } + else // Read from underlying stream + { + // Experimental code, blocks of page size + char[] chrs = new char[4096]; + int count = NextBlk(chrs, 0, 4096); + if (count == 0) + return EndOfFile; + else + { + data.Append(chrs, count); + return (int)data[bPos++]; + } + } + } + + public override string GetString(int begin, int limit) + { + return data.GetString(begin, limit); + } + + public override string ToString() + { + return "StringBuilder buffer, encoding: " + this.EncodingName; + } + } + + // =============== End ScanBuff-derived classes ================== + + public delegate int BlockReader(char[] block, int index, int number); + + // A delegate factory, serving up a delegate that + // reads a block of characters from the underlying + // encoded stream, via a StreamReader object. + // + public static class BlockReaderFactory + { + public static BlockReader Raw(Stream stream) + { + return delegate(char[] block, int index, int number) + { + byte[] b = new byte[number]; + int count = stream.Read(b, 0, number); + int i = 0; + int j = index; + for (; i < count; i++, j++) + block[j] = (char)b[i]; + return count; + }; + } + +#if (!BYTEMODE) + public static BlockReader Get(Stream stream, int fallbackCodePage) + { + Encoding encoding; + int preamble = Preamble(stream); + + if (preamble != 0) // There is a valid BOM here! + encoding = Encoding.GetEncoding(preamble); + else if (fallbackCodePage == -1) // Fallback is "raw" bytes + return Raw(stream); + else if (fallbackCodePage != -2) // Anything but "guess" + encoding = Encoding.GetEncoding(fallbackCodePage); + else // This is the "guess" option + { + int guess = new Guesser(stream).GuessCodePage(); + stream.Seek(0, SeekOrigin.Begin); + if (guess == -1) // ==> this is a 7-bit file + encoding = Encoding.ASCII; + else if (guess == 65001) + encoding = Encoding.UTF8; + else // ==> use the machine default + encoding = Encoding.Default; + } + StreamReader reader = new StreamReader(stream, encoding); + return reader.Read; + } + + static int Preamble(Stream stream) + { + int b0 = stream.ReadByte(); + int b1 = stream.ReadByte(); + + if (b0 == 0xfe && b1 == 0xff) + return 1201; // UTF16BE + if (b0 == 0xff && b1 == 0xfe) + return 1200; // UTF16LE + + int b2 = stream.ReadByte(); + if (b0 == 0xef && b1 == 0xbb && b2 == 0xbf) + return 65001; // UTF8 + // + // There is no unicode preamble, so we + // return denoter for the machine default. + // + stream.Seek(0, SeekOrigin.Begin); + return 0; + } +#endif // !BYTEMODE + } + #endregion Buffer classes + + // ============================================================== + // ============ class CodePageHandling ============= + // ============================================================== + + public static class CodePageHandling + { + public static int GetCodePage(string option) + { + string command = option.ToUpperInvariant(); + if (command.StartsWith("CodePage:", StringComparison.OrdinalIgnoreCase)) + command = command.Substring(9); + try + { + if (command.Equals("RAW")) + return -1; + else if (command.Equals("GUESS")) + return -2; + else if (command.Equals("DEFAULT")) + return 0; + else if (char.IsDigit(command[0])) + return int.Parse(command, CultureInfo.InvariantCulture); + else + { + Encoding enc = Encoding.GetEncoding(command); + return enc.CodePage; + } + } + catch (FormatException) + { + Console.Error.WriteLine( + "Invalid format \"{0}\", using machine default", option); + } + catch (ArgumentException) + { + Console.Error.WriteLine( + "Unknown code page \"{0}\", using machine default", option); + } + return 0; + } + } +#region guesser +#if (!BYTEMODE) + // ============================================================== + // ============ Encoding Guesser ============= + // ============================================================== + + /// <summary> + /// This class provides a simple finite state automaton that + /// scans the file looking for (1) valid UTF-8 byte patterns, + /// (2) bytes >= 0x80 which are not part of a UTF-8 sequence. + /// The method then guesses whether it is UTF-8 or maybe some + /// local machine default encoding. This works well for the + /// various Latin encodings. + /// </summary> + internal class Guesser + { + ScanBuff buffer; + + public int GuessCodePage() { return Scan(); } + + const int maxAccept = 10; + const int initial = 0; + const int eofNum = 0; + const int goStart = -1; + const int INITIAL = 0; + const int EndToken = 0; + + #region user code + /* + * Reads the bytes of a file to determine if it is + * UTF-8 or a single-byte code page file. + */ + public long utfX; + public long uppr; + #endregion user code + + int state; + int currentStart = startState[0]; + int code; + + #region ScannerTables + static int[] startState = new int[] { 11, 0 }; + + #region CharacterMap + static sbyte[] map = new sbyte[256] { +/* '\0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x10' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x20' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '@' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 'P' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '`' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 'p' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x80' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\x90' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xA0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xB0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xC0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* '\xD0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* '\xE0' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* '\xF0' */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5 }; + #endregion + + static sbyte[][] nextState = new sbyte[][] { + new sbyte[] {0, 0, 0, 0, 0, 0}, + new sbyte[] {-1, -1, 10, -1, -1, -1}, + new sbyte[] {-1, -1, -1, -1, -1, -1}, + new sbyte[] {-1, -1, 8, -1, -1, -1}, + new sbyte[] {-1, -1, 5, -1, -1, -1}, + new sbyte[] {-1, -1, 6, -1, -1, -1}, + new sbyte[] {-1, -1, 7, -1, -1, -1}, + null, + new sbyte[] {-1, -1, 9, -1, -1, -1}, + null, + null, + new sbyte[] {-1, 1, 2, 3, 4, 2} + }; + + + [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + // Reason for suppression: cannot have self-reference in array initializer. + static Guesser() + { + nextState[7] = nextState[2]; + nextState[9] = nextState[2]; + nextState[10] = nextState[2]; + } + + int NextState() + { + if (code == ScanBuff.EndOfFile) + return eofNum; + else + return nextState[state][map[code]]; + } + #endregion + + public Guesser(System.IO.Stream file) { SetSource(file); } + + public void SetSource(System.IO.Stream source) + { + this.buffer = new BuildBuffer(source); + code = buffer.Read(); + } + + int Scan() + { + for (; ; ) + { + int next; + state = currentStart; + while ((next = NextState()) == goStart) + code = buffer.Read(); + + state = next; + code = buffer.Read(); + + while ((next = NextState()) > eofNum) + { + state = next; + code = buffer.Read(); + } + if (state <= maxAccept) + { + #region ActionSwitch +#pragma warning disable 162 + switch (state) + { + case eofNum: + switch (currentStart) + { + case 11: + if (utfX == 0 && uppr == 0) return -1; /* raw ascii */ + else if (uppr * 10 > utfX) return 0; /* default code page */ + else return 65001; /* UTF-8 encoding */ + break; + } + return EndToken; + case 1: // Recognized '{Upper128}', Shortest string "\xC0" + case 2: // Recognized '{Upper128}', Shortest string "\x80" + case 3: // Recognized '{Upper128}', Shortest string "\xE0" + case 4: // Recognized '{Upper128}', Shortest string "\xF0" + uppr++; + break; + case 5: // Recognized '{Utf8pfx4}{Utf8cont}', Shortest string "\xF0\x80" + uppr += 2; + break; + case 6: // Recognized '{Utf8pfx4}{Utf8cont}{2}', Shortest string "\xF0\x80\x80" + uppr += 3; + break; + case 7: // Recognized '{Utf8pfx4}{Utf8cont}{3}', Shortest string "\xF0\x80\x80\x80" + utfX += 3; + break; + case 8: // Recognized '{Utf8pfx3}{Utf8cont}', Shortest string "\xE0\x80" + uppr += 2; + break; + case 9: // Recognized '{Utf8pfx3}{Utf8cont}{2}', Shortest string "\xE0\x80\x80" + utfX += 2; + break; + case 10: // Recognized '{Utf8pfx2}{Utf8cont}', Shortest string "\xC0\x80" + utfX++; + break; + default: + break; + } +#pragma warning restore 162 + #endregion + } + } + } + } // end class Guesser + +#endif // !BYTEMODE +#endregion + +// End of code copied from embedded resource + +} // end namespace diff --git a/Module6/SimpleLanguage1/SimpleLex.lex b/Module6/SimpleLanguage1/SimpleLex.lex new file mode 100644 index 0000000..20b364f --- /dev/null +++ b/Module6/SimpleLanguage1/SimpleLex.lex @@ -0,0 +1,78 @@ +%using SimpleParser; +%using QUT.Gppg; +%using System.Linq; + +%namespace SimpleScanner + +Alpha [a-zA-Z_] +Digit [0-9] +AlphaDigit {Alpha}|{Digit} +INTNUM {Digit}+ +REALNUM {INTNUM}\.{INTNUM} +ID {Alpha}{AlphaDigit}* + +%% + +{INTNUM} { + yylval.iVal = int.Parse(yytext); + return (int)Tokens.INUM; +} + +{REALNUM} { + yylval.dVal = double.Parse(yytext); + return (int)Tokens.RNUM; +} + +{ID} { + int res = ScannerHelper.GetIDToken(yytext); + if (res == (int)Tokens.ID) + yylval.sVal = yytext; + return res; +} + +":=" { return (int)Tokens.ASSIGN; } +";" { return (int)Tokens.SEMICOLON; } + +[^ \r\n] { + LexError(); +} + +%{ + yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); +%} + +%% + +public override void yyerror(string format, params object[] args) // обработка синтаксических ошибок +{ + var ww = args.Skip(1).Cast<string>().ToArray(); + string errorMsg = string.Format("({0},{1}): Встречено {2}, а ожидалось {3}", yyline, yycol, args[0], string.Join(" или ", ww)); + throw new SyntaxException(errorMsg); +} + +public void LexError() +{ + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); + throw new LexException(errorMsg); +} + +class ScannerHelper +{ + private static Dictionary<string,int> keywords; + + static ScannerHelper() + { + keywords = new Dictionary<string,int>(); + keywords.Add("begin",(int)Tokens.BEGIN); + keywords.Add("end",(int)Tokens.END); + keywords.Add("cycle",(int)Tokens.CYCLE); + } + public static int GetIDToken(string s) + { + if (keywords.ContainsKey(s.ToLower())) + return keywords[s]; + else + return (int)Tokens.ID; + } + +} diff --git a/Module6/SimpleLanguage1/SimpleYacc.cs b/Module6/SimpleLanguage1/SimpleYacc.cs new file mode 100644 index 0000000..5666e24 --- /dev/null +++ b/Module6/SimpleLanguage1/SimpleYacc.cs @@ -0,0 +1,166 @@ +// This code was generated by the Gardens Point Parser Generator +// Copyright (c) Wayne Kelly, QUT 2005-2010 +// (see accompanying GPPGcopyright.rtf) + +// GPPG version 1.3.6 +// Machine: HUB +// DateTime: 21.09.2017 20:37:24 +// UserName: someone +// Input file <SimpleYacc.y> + +// options: no-lines gplex + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using QUT.Gppg; +using ProgramTree; + +namespace SimpleParser +{ +public enum Tokens { + error=1,EOF=2,BEGIN=3,END=4,CYCLE=5,ASSIGN=6, + SEMICOLON=7,INUM=8,RNUM=9,ID=10}; + +public struct ValueType +{ + public double dVal; + public int iVal; + public string sVal; + public Node nVal; + public ExprNode eVal; + public StatementNode stVal; + public BlockNode blVal; + } +// Abstract base class for GPLEX scanners +public abstract class ScanBase : AbstractScanner<ValueType,LexLocation> { + private LexLocation __yylloc = new LexLocation(); + public override LexLocation yylloc { get { return __yylloc; } set { __yylloc = value; } } + protected virtual bool yywrap() { return true; } +} + +public class Parser: ShiftReduceParser<ValueType, LexLocation> +{ + // Verbatim content from SimpleYacc.y +// Эти объявления добавляются в класс GPPGParser, представляющий собой парсер, генерируемый системой gppg + public BlockNode root; // Корневой узел синтаксического дерева + public Parser(AbstractScanner<ValueType, LexLocation> scanner) : base(scanner) { } + // End verbatim content from SimpleYacc.y + +#pragma warning disable 649 + private static Dictionary<int, string> aliasses; +#pragma warning restore 649 + private static Rule[] rules = new Rule[14]; + private static State[] states = new State[22]; + private static string[] nonTerms = new string[] { + "expr", "ident", "assign", "statement", "cycle", "stlist", "block", "progr", + "$accept", }; + + static Parser() { + states[0] = new State(new int[]{3,4},new int[]{-8,1,-7,3}); + states[1] = new State(new int[]{2,2}); + states[2] = new State(-1); + states[3] = new State(-2); + states[4] = new State(new int[]{10,14,3,4,5,18},new int[]{-6,5,-4,21,-3,9,-2,10,-7,16,-5,17}); + states[5] = new State(new int[]{4,6,7,7}); + states[6] = new State(-12); + states[7] = new State(new int[]{10,14,3,4,5,18},new int[]{-4,8,-3,9,-2,10,-7,16,-5,17}); + states[8] = new State(-4); + states[9] = new State(-5); + states[10] = new State(new int[]{6,11}); + states[11] = new State(new int[]{10,14,8,15},new int[]{-1,12,-2,13}); + states[12] = new State(-9); + states[13] = new State(-10); + states[14] = new State(-8); + states[15] = new State(-11); + states[16] = new State(-6); + states[17] = new State(-7); + states[18] = new State(new int[]{10,14,8,15},new int[]{-1,19,-2,13}); + states[19] = new State(new int[]{10,14,3,4,5,18},new int[]{-4,20,-3,9,-2,10,-7,16,-5,17}); + states[20] = new State(-13); + states[21] = new State(-3); + + rules[1] = new Rule(-9, new int[]{-8,2}); + rules[2] = new Rule(-8, new int[]{-7}); + rules[3] = new Rule(-6, new int[]{-4}); + rules[4] = new Rule(-6, new int[]{-6,7,-4}); + rules[5] = new Rule(-4, new int[]{-3}); + rules[6] = new Rule(-4, new int[]{-7}); + rules[7] = new Rule(-4, new int[]{-5}); + rules[8] = new Rule(-2, new int[]{10}); + rules[9] = new Rule(-3, new int[]{-2,6,-1}); + rules[10] = new Rule(-1, new int[]{-2}); + rules[11] = new Rule(-1, new int[]{8}); + rules[12] = new Rule(-7, new int[]{3,-6,4}); + rules[13] = new Rule(-5, new int[]{5,-1,-4}); + } + + protected override void Initialize() { + this.InitSpecialTokens((int)Tokens.error, (int)Tokens.EOF); + this.InitStates(states); + this.InitRules(rules); + this.InitNonTerminals(nonTerms); + } + + protected override void DoAction(int action) + { + switch (action) + { + case 2: // progr -> block +{ root = ValueStack[ValueStack.Depth-1].blVal; } + break; + case 3: // stlist -> statement +{ + CurrentSemanticValue.blVal = new BlockNode(ValueStack[ValueStack.Depth-1].stVal); + } + break; + case 4: // stlist -> stlist, SEMICOLON, statement +{ + ValueStack[ValueStack.Depth-3].blVal.Add(ValueStack[ValueStack.Depth-1].stVal); + CurrentSemanticValue.blVal = ValueStack[ValueStack.Depth-3].blVal; + } + break; + case 5: // statement -> assign +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 6: // statement -> block +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].blVal; } + break; + case 7: // statement -> cycle +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 8: // ident -> ID +{ CurrentSemanticValue.eVal = new IdNode(ValueStack[ValueStack.Depth-1].sVal); } + break; + case 9: // assign -> ident, ASSIGN, expr +{ CurrentSemanticValue.stVal = new AssignNode(ValueStack[ValueStack.Depth-3].eVal as IdNode, ValueStack[ValueStack.Depth-1].eVal); } + break; + case 10: // expr -> ident +{ CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal as IdNode; } + break; + case 11: // expr -> INUM +{ CurrentSemanticValue.eVal = new IntNumNode(ValueStack[ValueStack.Depth-1].iVal); } + break; + case 12: // block -> BEGIN, stlist, END +{ CurrentSemanticValue.blVal = ValueStack[ValueStack.Depth-2].blVal; } + break; + case 13: // cycle -> CYCLE, expr, statement +{ CurrentSemanticValue.stVal = new CycleNode(ValueStack[ValueStack.Depth-2].eVal, ValueStack[ValueStack.Depth-1].stVal); } + break; + } + } + + protected override string TerminalToString(int terminal) + { + if (aliasses != null && aliasses.ContainsKey(terminal)) + return aliasses[terminal]; + else if (((Tokens)terminal).ToString() != terminal.ToString(CultureInfo.InvariantCulture)) + return ((Tokens)terminal).ToString(); + else + return CharToString((char)terminal); + } + + +} +} diff --git a/Module6/SimpleLanguage1/SimpleYacc.y b/Module6/SimpleLanguage1/SimpleYacc.y new file mode 100644 index 0000000..b9899b4 --- /dev/null +++ b/Module6/SimpleLanguage1/SimpleYacc.y @@ -0,0 +1,70 @@ +%{ +// Эти объявления добавляются в класс GPPGParser, представляющий собой парсер, генерируемый системой gppg + public BlockNode root; // Корневой узел синтаксического дерева + public Parser(AbstractScanner<ValueType, LexLocation> scanner) : base(scanner) { } +%} + +%output = SimpleYacc.cs + +%union { + public double dVal; + public int iVal; + public string sVal; + public Node nVal; + public ExprNode eVal; + public StatementNode stVal; + public BlockNode blVal; + } + +%using ProgramTree; + +%namespace SimpleParser + +%token BEGIN END CYCLE ASSIGN SEMICOLON +%token <iVal> INUM +%token <dVal> RNUM +%token <sVal> ID + +%type <eVal> expr ident +%type <stVal> assign statement cycle +%type <blVal> stlist block + +%% + +progr : block { root = $1; } + ; + +stlist : statement + { + $$ = new BlockNode($1); + } + | stlist SEMICOLON statement + { + $1.Add($3); + $$ = $1; + } + ; + +statement: assign { $$ = $1; } + | block { $$ = $1; } + | cycle { $$ = $1; } + ; + +ident : ID { $$ = new IdNode($1); } + ; + +assign : ident ASSIGN expr { $$ = new AssignNode($1 as IdNode, $3); } + ; + +expr : ident { $$ = $1 as IdNode; } + | INUM { $$ = new IntNumNode($1); } + ; + +block : BEGIN stlist END { $$ = $2; } + ; + +cycle : CYCLE expr statement { $$ = new CycleNode($2, $3); } + ; + +%% + diff --git a/Module6/SimpleLanguage1/a.txt b/Module6/SimpleLanguage1/a.txt new file mode 100644 index 0000000..52ea170 --- /dev/null +++ b/Module6/SimpleLanguage1/a.txt @@ -0,0 +1,10 @@ +begin + b := 2; + a := 3; + a := b; + cycle 3 + begin + a := c; + c := 1 + end +end diff --git a/Module6/SimpleLanguage1/generateParserScanner.bat b/Module6/SimpleLanguage1/generateParserScanner.bat new file mode 100644 index 0000000..7ca5476 --- /dev/null +++ b/Module6/SimpleLanguage1/generateParserScanner.bat @@ -0,0 +1,3 @@ +cls +gplex.exe /unicode SimpleLex.lex +gppg.exe /no-lines /gplex SimpleYacc.y diff --git a/Module7/SimpleLanguage2/Main.cs b/Module7/SimpleLanguage2/Main.cs new file mode 100644 index 0000000..3734ff4 --- /dev/null +++ b/Module7/SimpleLanguage2/Main.cs @@ -0,0 +1,56 @@ +п»їusing System; +using System.IO; +using System.Text; +using System.Reflection; +using System.Collections.Generic; +using SimpleScanner; +using SimpleParser; +using SimpleLang.Visitors; + +namespace SimpleCompiler +{ + public class SimpleCompilerMain + { + public static void Main() + { + string FileName = @"..\..\a.txt"; + try + { + string Text = File.ReadAllText(FileName); + + Scanner scanner = new Scanner(); + scanner.SetSource(Text, 0); + + Parser parser = new Parser(scanner); + + var b = parser.Parse(); + if (!b) + Console.WriteLine("Ошибка"); + else + { + Console.WriteLine("Синтаксическое дерево построено"); + + var avis = new AssignCountVisitor(); + parser.root.Visit(avis); + Console.WriteLine("Количество присваиваний = {0}", avis.Count); + Console.WriteLine("-------------------------------"); + + var pp = new PrettyPrintVisitor(); + parser.root.Visit(pp); + Console.WriteLine(pp.Text); + } + } + catch (FileNotFoundException) + { + Console.WriteLine("Файл {0} РЅРµ найден", FileName); + } + catch (Exception e) + { + Console.WriteLine("{0}", e); + } + + Console.ReadLine(); + } + + } +} diff --git a/Module7/SimpleLanguage2/ParserHelper.cs b/Module7/SimpleLanguage2/ParserHelper.cs new file mode 100644 index 0000000..a085ecd --- /dev/null +++ b/Module7/SimpleLanguage2/ParserHelper.cs @@ -0,0 +1,33 @@ +п»їusing System.Collections.Generic; +using System; + +namespace SimpleParser +{ + + public enum type { tint, tdouble }; + + public static class SymbolTable // Таблица символов + { + public static Dictionary<string, type> vars = new Dictionary<string, type>(); // таблица символов + public static void NewVarDef(string name, type t) + { + if (vars.ContainsKey(name)) + throw new Exception("Переменная " + name + " уже определена"); + else vars.Add(name, t); + } + } + + public class LexException : Exception + { + public LexException(string msg) : base(msg) { } + } + + public class SyntaxException : Exception + { + public SyntaxException(string msg) : base(msg) { } + } + + public static class ParserHelper + { + } +} \ No newline at end of file diff --git a/Module7/SimpleLanguage2/ProgramTree.cs b/Module7/SimpleLanguage2/ProgramTree.cs new file mode 100644 index 0000000..e48dcb5 --- /dev/null +++ b/Module7/SimpleLanguage2/ProgramTree.cs @@ -0,0 +1,145 @@ +п»їusing System.Collections.Generic; +using SimpleLang.Visitors; + +namespace ProgramTree +{ + public enum AssignType { Assign, AssignPlus, AssignMinus, AssignMult, AssignDivide }; + + public abstract class Node // базовый класс для всех узлов + { + public abstract void Visit(Visitor v); + } + + public abstract class ExprNode : Node // базовый класс для всех выражений + { + } + + public class IdNode : ExprNode + { + public string Name { get; set; } + public IdNode(string name) { Name = name; } + public override void Visit(Visitor v) + { + v.VisitIdNode(this); + } + } + + public class IntNumNode : ExprNode + { + public int Num { get; set; } + public IntNumNode(int num) { Num = num; } + public override void Visit(Visitor v) + { + v.VisitIntNumNode(this); + } + } + + public class BinOpNode : ExprNode + { + public ExprNode Left { get; set; } + public ExprNode Right { get; set; } + public char Op { get; set; } + public BinOpNode(ExprNode Left, ExprNode Right, char op) + { + this.Left = Left; + this.Right = Right; + this.Op = op; + } + public override void Visit(Visitor v) + { + v.VisitBinOpNode(this); + } + } + + public abstract class StatementNode : Node // базовый класс для всех операторов + { + } + + public class AssignNode : StatementNode + { + public IdNode Id { get; set; } + public ExprNode Expr { get; set; } + public AssignType AssOp { get; set; } + public AssignNode(IdNode id, ExprNode expr, AssignType assop = AssignType.Assign) + { + Id = id; + Expr = expr; + AssOp = assop; + } + public override void Visit(Visitor v) + { + v.VisitAssignNode(this); + } + } + + public class CycleNode : StatementNode + { + public ExprNode Expr { get; set; } + public StatementNode Stat { get; set; } + public CycleNode(ExprNode expr, StatementNode stat) + { + Expr = expr; + Stat = stat; + } + public override void Visit(Visitor v) + { + v.VisitCycleNode(this); + } + } + + public class BlockNode : StatementNode + { + public List<StatementNode> StList = new List<StatementNode>(); + public BlockNode(StatementNode stat) + { + Add(stat); + } + public void Add(StatementNode stat) + { + StList.Add(stat); + } + public override void Visit(Visitor v) + { + v.VisitBlockNode(this); + } + } + + public class WriteNode : StatementNode + { + public ExprNode Expr { get; set; } + public WriteNode(ExprNode Expr) + { + this.Expr = Expr; + } + public override void Visit(Visitor v) + { + v.VisitWriteNode(this); + } + } + + public class EmptyNode : StatementNode + { + public override void Visit(Visitor v) + { + v.VisitEmptyNode(this); + } + } + + public class VarDefNode : StatementNode + { + public List<IdNode> vars = new List<IdNode>(); + public VarDefNode(IdNode id) + { + Add(id); + } + + public void Add(IdNode id) + { + vars.Add(id); + } + public override void Visit(Visitor v) + { + v.VisitVarDefNode(this); + } + } +} \ No newline at end of file diff --git a/Module7/SimpleLanguage2/Properties/AssemblyInfo.cs b/Module7/SimpleLanguage2/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..896cc99 --- /dev/null +++ b/Module7/SimpleLanguage2/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +п»їusing System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Управление общими сведениями Рѕ СЃР±РѕСЂРєРµ осуществляется СЃ помощью +// набора атрибутов. Рзмените значения этих атрибутов, чтобы изменить сведения, +// связанные СЃРѕ СЃР±РѕСЂРєРѕР№. +[assembly: AssemblyTitle("SimpleLang")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SimpleLang")] +[assembly: AssemblyCopyright("Copyright В© 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Параметр ComVisible СЃРѕ значением FALSE делает типы РІ СЃР±РѕСЂРєРµ невидимыми +// для COM-компонентов. Если требуется обратиться Рє типу РІ этой СЃР±РѕСЂРєРµ через +// COM, задайте атрибуту ComVisible значение TRUE для этого типа. +[assembly: ComVisible(false)] + +// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM +[assembly: Guid("06dba63f-4805-4cd3-8a93-b329b2c7e37b")] + +// Сведения Рѕ версии СЃР±РѕСЂРєРё состоят РёР· следующих четырех значений: +// +// РћСЃРЅРѕРІРЅРѕР№ номер версии +// Дополнительный номер версии +// Номер построения +// Редакция +// +// Можно задать РІСЃРµ значения или принять номер построения Рё номер редакции РїРѕ умолчанию, +// используя "*", как показано ниже: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Module7/SimpleLanguage2/ShiftReduceParserCode.cs b/Module7/SimpleLanguage2/ShiftReduceParserCode.cs new file mode 100644 index 0000000..c110ba1 --- /dev/null +++ b/Module7/SimpleLanguage2/ShiftReduceParserCode.cs @@ -0,0 +1,944 @@ +// Gardens Point Parser Generator +// Copyright (c) Wayne Kelly, QUT 2005-2009 +// (see accompanying GPPGcopyright.rtf) +#define EXPORT_GPPG + +using System; +using System.Text; +using System.Globalization; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; + +namespace QUT.Gppg +{ + /// <summary> + /// Abstract class for GPPG shift-reduce parsers. + /// Parsers generated by GPPG derive from this base + /// class, overriding the abstract Initialize() and + /// DoAction() methods. + /// </summary> + /// <typeparam name="TValue">Semantic value type</typeparam> + /// <typeparam name="TSpan">Location type</typeparam> +#if EXPORT_GPPG + public abstract class ShiftReduceParser<TValue, TSpan> +#else + internal abstract class ShiftReduceParser<TValue, TSpan> +#endif + where TSpan : IMerge<TSpan>, new() + { + public AbstractScanner<TValue, TSpan> scanner; + /// <summary> + /// The abstract scanner for this parser. + /// </summary> + protected AbstractScanner<TValue, TSpan> Scanner { + get { return scanner; } + set { scanner = value; } + } + + /// <summary> + /// Constructor for base class + /// </summary> + /// <param name="scanner">Scanner instance for this parser</param> + protected ShiftReduceParser(AbstractScanner<TValue, TSpan> scanner) + { + this.scanner = scanner; + } + + // ============================================================== + // TECHNICAL EXPLANATION. + // Why the next two fields are not exposed via properties. + // ============================================================== + // These fields are of the generic parameter types, and are + // frequently instantiated as struct types in derived classes. + // Semantic actions are defined in the derived classes and refer + // to instance fields of these structs. Is such cases the code + // "get_CurrentSemanticValue().myField = blah;" will fail since + // the getter pushes the value of the field, not the reference. + // So, in the presence of properties, gppg would need to encode + // such field accesses as ... + // "tmp = get_CurrentSemanticValue(); // Fetch value + // tmp.myField = blah; // update + // set_CurrentSemanticValue(tmp); " // Write update back. + // There is no issue if TValue is restricted to be a ref type. + // The same explanation applies to scanner.yylval. + // ============================================================== + /// <summary> + /// The current value of the "$$" symbolic variable in the parser + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + protected TValue CurrentSemanticValue; + + /// <summary> + /// The current value of the "@$" symbolic variable in the parser + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + protected TSpan CurrentLocationSpan; + + private TSpan LastSpan; + private int NextToken; + private State FsaState; + private bool recovering; + private int tokensSinceLastError; + + private PushdownPrefixState<State> StateStack = new PushdownPrefixState<State>(); + private PushdownPrefixState<TValue> valueStack = new PushdownPrefixState<TValue>(); + private PushdownPrefixState<TSpan> locationStack = new PushdownPrefixState<TSpan>(); + + /// <summary> + /// The stack of semantic value (YYSTYPE) values. + /// </summary> + protected PushdownPrefixState<TValue> ValueStack { get { return valueStack; } } + + /// <summary> + /// The stack of location value (YYLTYPE) varlues. + /// </summary> + protected PushdownPrefixState<TSpan> LocationStack { get { return locationStack; } } + + private int errorToken; + private int endOfFileToken; + private string[] nonTerminals; + private State[] states; + private Rule[] rules; + + /// <summary> + /// Initialization method to allow derived classes + /// to insert the rule list into this base class. + /// </summary> + /// <param name="rules">The array of Rule objects</param> + protected void InitRules(Rule[] rules) { this.rules = rules; } + + /// <summary> + /// Initialization method to allow derived classes to + /// insert the states table into this base class. + /// </summary> + /// <param name="states">The pre-initialized states table</param> + protected void InitStates(State[] states) { this.states = states; } + + /// <summary> + /// OBSOLETE FOR VERSION 1.4.0 + /// </summary> + /// <param name="size"></param> + protected void InitStateTable(int size) { states = new State[size]; } + + /// <summary> + /// Initialization method to allow derived classes + /// to insert the special value for the error and EOF tokens. + /// </summary> + /// <param name="err">The error state ordinal</param> + /// <param name="end">The EOF stat ordinal</param> + protected void InitSpecialTokens(int err, int end) + { + errorToken = err; + endOfFileToken = end; + } + + /// <summary> + /// Initialization method to allow derived classes to + /// insert the non-terminal symbol names into this base class. + /// </summary> + /// <param name="names">Non-terminal symbol names</param> + protected void InitNonTerminals(string[] names) { nonTerminals = names; } + + #region YYAbort, YYAccept etcetera. + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class AcceptException : Exception + { + internal AcceptException() { } + protected AcceptException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class AbortException : Exception + { + internal AbortException() { } + protected AbortException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class ErrorException : Exception + { + internal ErrorException() { } + protected ErrorException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + + // The following methods are only called from within + // a semantic action. The thrown exceptions can never + // propagate outside the ShiftReduceParser class in + // which they are nested. + + /// <summary> + /// Force parser to terminate, returning "true" + /// </summary> + protected static void YYAccept() { throw new AcceptException(); } + + /// <summary> + /// Force parser to terminate, returning "false" + /// </summary> + protected static void YYAbort() { throw new AbortException(); } + + /// <summary> + /// Force parser to terminate, returning + /// "false" if error recovery fails. + /// </summary> + protected static void YYError() { throw new ErrorException(); } + + /// <summary> + /// Check if parser in error recovery state. + /// </summary> + protected bool YYRecovering { get { return recovering; } } + #endregion + + /// <summary> + /// Abstract base method. ShiftReduceParser calls this + /// to initialize the base class data structures. Concrete + /// parser classes must override this method. + /// </summary> + protected abstract void Initialize(); + + /// <summary> + /// Main entry point of the Shift-Reduce Parser. + /// </summary> + /// <returns>True if parse succeeds, else false for + /// unrecoverable errors</returns> + public bool Parse() + { + Initialize(); // allow derived classes to instantiate rules, states and nonTerminals + + NextToken = 0; + FsaState = states[0]; + + StateStack.Push(FsaState); + valueStack.Push(CurrentSemanticValue); + LocationStack.Push(CurrentLocationSpan); + + while (true) + { +#if TRACE_ACTIONS + Console.Error.WriteLine("Entering state {0} ", FsaState.number); +#endif + int action = FsaState.defaultAction; + + if (FsaState.ParserTable != null) + { + if (NextToken == 0) + { +#if TRACE_ACTIONS + Console.Error.Write("Reading a token: "); +#endif + // We save the last token span, so that the location span + // of production right hand sides that begin or end with a + // nullable production will be correct. + LastSpan = scanner.yylloc; + NextToken = scanner.yylex(); + } + +#if TRACE_ACTIONS + Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken)); +#endif + if (FsaState.ParserTable.ContainsKey(NextToken)) + action = FsaState.ParserTable[NextToken]; + } + + if (action > 0) // shift + { + Shift(action); + } + else if (action < 0) // reduce + { + try + { + Reduce(-action); + if (action == -1) // accept + return true; + } + catch (Exception x) + { + if (x is AbortException) + return false; + else if (x is AcceptException) + return true; + else if (x is ErrorException && !ErrorRecovery()) + return false; + else + throw; // Rethrow x, preserving information. + + } + } + else if (action == 0) // error + if (!ErrorRecovery()) + return false; + } + } + + private void Shift(int stateIndex) + { +#if TRACE_ACTIONS + Console.Error.Write("Shifting token {0}, ", TerminalToString(NextToken)); +#endif + FsaState = states[stateIndex]; + + valueStack.Push(scanner.yylval); + StateStack.Push(FsaState); + LocationStack.Push(scanner.yylloc); + + if (recovering) + { + if (NextToken != errorToken) + tokensSinceLastError++; + + if (tokensSinceLastError > 5) + recovering = false; + } + + if (NextToken != endOfFileToken) + NextToken = 0; + } + + private void Reduce(int ruleNumber) + { +#if TRACE_ACTIONS + DisplayRule(ruleNumber); +#endif + Rule rule = rules[ruleNumber]; + // + // Default actions for unit productions. + // + if (rule.RightHandSide.Length == 1) + { + CurrentSemanticValue = valueStack.TopElement(); // Default action: $$ = $1; + CurrentLocationSpan = LocationStack.TopElement(); // Default action "@$ = @1; + } + else + { + if (rule.RightHandSide.Length == 0) + { + // Create a new blank value. + // Explicit semantic action may mutate this value + CurrentSemanticValue = default(TValue); + // The location span for an empty production will start with the + // beginning of the next lexeme, and end with the finish of the + // previous lexeme. This gives the correct behaviour when this + // nonsense value is used in later Merge operations. + CurrentLocationSpan = (scanner.yylloc != null && LastSpan != null ? + scanner.yylloc.Merge(LastSpan) : + default(TSpan)); + } + else + { + // Default action: $$ = $1; + CurrentSemanticValue = valueStack.TopElement(); + // Default action "@$ = @1.Merge(@N)" for location info. + TSpan at1 = LocationStack[LocationStack.Depth - rule.RightHandSide.Length]; + TSpan atN = LocationStack[LocationStack.Depth - 1]; + CurrentLocationSpan = + ((at1 != null && atN != null) ? at1.Merge(atN) : default(TSpan)); + } + } + + DoAction(ruleNumber); + + for (int i = 0; i < rule.RightHandSide.Length; i++) + { + StateStack.Pop(); + valueStack.Pop(); + LocationStack.Pop(); + } + +#if TRACE_ACTIONS + DisplayStack(); +#endif + FsaState = StateStack.TopElement(); + + if (FsaState.Goto.ContainsKey(rule.LeftHandSide)) + FsaState = states[FsaState.Goto[rule.LeftHandSide]]; + + StateStack.Push(FsaState); + valueStack.Push(CurrentSemanticValue); + LocationStack.Push(CurrentLocationSpan); + } + + /// <summary> + /// Execute the selected action from array. + /// Must be overriden in derived classes. + /// </summary> + /// <param name="actionNumber">Index of the action to perform</param> + protected abstract void DoAction(int actionNumber); + + private bool ErrorRecovery() + { + bool discard; + + if (!recovering) // if not recovering from previous error + ReportError(); + + if (!FindErrorRecoveryState()) + return false; + // + // The interim fix for the "looping in error recovery" + // artifact involved moving the setting of the recovering + // bool until after invalid tokens have been discarded. + // + ShiftErrorToken(); + discard = DiscardInvalidTokens(); + recovering = true; + tokensSinceLastError = 0; + return discard; + } + + private void ReportError1() + { + StringBuilder errorMsg = new StringBuilder(); + errorMsg.AppendFormat("Syntax error, unexpected {0}", TerminalToString(NextToken)); + + if (FsaState.ParserTable.Count < 7) + { + bool first = true; + foreach (int terminal in FsaState.ParserTable.Keys) + { + if (first) + errorMsg.Append(", expecting "); + else + errorMsg.Append(", or "); + + errorMsg.Append(TerminalToString(terminal)); + first = false; + } + } + scanner.yyerror(errorMsg.ToString()); + } + + private void ReportError() + { + object[] args = new object[FsaState.ParserTable.Keys.Count+1]; + args[0] = TerminalToString(NextToken); + int i=1; + foreach (int terminal in FsaState.ParserTable.Keys) + { + args[i] = TerminalToString(terminal); + i++; + } + scanner.yyerror("",args); + } + + private void ShiftErrorToken() + { + int old_next = NextToken; + NextToken = errorToken; + + Shift(FsaState.ParserTable[NextToken]); + +#if TRACE_ACTIONS + Console.Error.WriteLine("Entering state {0} ", FsaState.number); +#endif + NextToken = old_next; + } + + private bool FindErrorRecoveryState() + { + while (true) // pop states until one found that accepts error token + { + if (FsaState.ParserTable != null && + FsaState.ParserTable.ContainsKey(errorToken) && + FsaState.ParserTable[errorToken] > 0) // shift + return true; + +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: popping state {0}", StateStack.Top().number); +#endif + StateStack.Pop(); + valueStack.Pop(); + LocationStack.Pop(); + +#if TRACE_ACTIONS + DisplayStack(); +#endif + if (StateStack.IsEmpty()) + { +#if TRACE_ACTIONS + Console.Error.Write("Aborting: didn't find a state that accepts error token"); +#endif + return false; + } + else + FsaState = StateStack.TopElement(); + } + } + + private bool DiscardInvalidTokens() + { + + int action = FsaState.defaultAction; + + if (FsaState.ParserTable != null) + { + // Discard tokens until find one that works ... + while (true) + { + if (NextToken == 0) + { +#if TRACE_ACTIONS + Console.Error.Write("Reading a token: "); +#endif + NextToken = scanner.yylex(); + } + +#if TRACE_ACTIONS + Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken)); +#endif + if (NextToken == endOfFileToken) + return false; + + if (FsaState.ParserTable.ContainsKey(NextToken)) + action = FsaState.ParserTable[NextToken]; + + if (action != 0) + return true; + else + { +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: Discarding {0}", TerminalToString(NextToken)); +#endif + NextToken = 0; + } + } + } + else if (recovering && tokensSinceLastError == 0) + { + // + // Boolean recovering is not set until after the first + // error token has been shifted. Thus if we get back + // here with recovering set and no tokens read we are + // looping on the same error recovery action. This + // happens if current_state.ParserTable is null because + // the state has an LR(0) reduction, but not all + // lookahead tokens are valid. This only occurs for + // error productions that *end* on "error". + // + // This action discards tokens one at a time until + // the looping stops. Another attack would be to always + // use the LALR(1) table if a production ends on "error" + // +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: panic discard of {0}", TerminalToString(NextToken)); +#endif + if (NextToken == endOfFileToken) + return false; + NextToken = 0; + return true; + } + else + return true; + + } + + /// <summary> + /// Traditional YACC method. Discards the next input token. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyclearin")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyclearin")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + protected void yyclearin() { NextToken = 0; } + + /// <summary> + /// Tradional YACC method. Clear the "recovering" flag. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerrok")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerrok")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + protected void yyerrok() + { + recovering = false; + } + + /// <summary> + /// OBSOLETE FOR VERSION 1.4.0 + /// Method used by derived types to insert new + /// state instances in the "states" array. + /// </summary> + /// <param name="stateNumber">index of the state</param> + /// <param name="state">data for the state</param> + protected void AddState(int stateNumber, State state) + { + states[stateNumber] = state; + state.number = stateNumber; + } + + private void DisplayStack() + { + Console.Error.Write("State now"); + for (int i = 0; i < StateStack.Depth; i++) + Console.Error.Write(" {0}", StateStack[i].number); + Console.Error.WriteLine(); + } + + private void DisplayRule(int ruleNumber) + { + Console.Error.Write("Reducing stack by rule {0}, ", ruleNumber); + DisplayProduction(rules[ruleNumber]); + } + + private void DisplayProduction(Rule rule) + { + if (rule.RightHandSide.Length == 0) + Console.Error.Write("/* empty */ "); + else + foreach (int symbol in rule.RightHandSide) + Console.Error.Write("{0} ", SymbolToString(symbol)); + + Console.Error.WriteLine("-> {0}", SymbolToString(rule.LeftHandSide)); + } + + /// <summary> + /// Abstract state class naming terminal symbols. + /// This is overridden by derived classes with the + /// name (or alias) to be used in error messages. + /// </summary> + /// <param name="terminal">The terminal ordinal</param> + /// <returns></returns> + protected abstract string TerminalToString(int terminal); + + private string SymbolToString(int symbol) + { + if (symbol < 0) + return nonTerminals[-symbol]; + else + return TerminalToString(symbol); + } + + /// <summary> + /// Return text representation of argument character + /// </summary> + /// <param name="input">The character to convert</param> + /// <returns>String representation of the character</returns> + protected static string CharToString(char input) + { + switch (input) + { + case '\a': return @"'\a'"; + case '\b': return @"'\b'"; + case '\f': return @"'\f'"; + case '\n': return @"'\n'"; + case '\r': return @"'\r'"; + case '\t': return @"'\t'"; + case '\v': return @"'\v'"; + case '\0': return @"'\0'"; + default: return string.Format(CultureInfo.InvariantCulture, "'{0}'", input); + } + } + } + + /// <summary> + /// Classes implementing this interface must supply a + /// method that merges two location objects to return + /// a new object of the same type. + /// GPPG-generated parsers have the default location + /// action equivalent to "@$ = @1.Merge(@N);" where N + /// is the right-hand-side length of the production. + /// </summary> + /// <typeparam name="TSpan">The Location type</typeparam> +#if EXPORT_GPPG + public interface IMerge<TSpan> +#else + internal interface IMerge<TSpan> +#endif + { + /// <summary> + /// Interface method that creates a location object from + /// the current and last object. Typically used to create + /// a location object extending from the start of the @1 + /// object to the end of the @N object. + /// </summary> + /// <param name="last">The lexically last object to merge</param> + /// <returns>The merged location object</returns> + TSpan Merge(TSpan last); + } + + /// <summary> + /// This is the default class that carries location + /// information from the scanner to the parser. + /// If you don't declare "%YYLTYPE Foo" the parser + /// will expect to deal with this type. + /// </summary> +#if EXPORT_GPPG + public class LexLocation : IMerge<LexLocation> +#else + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + internal class LexLocation : IMerge<LexLocation> +#endif + { + private int startLine; // start line + private int startColumn; // start column + private int endLine; // end line + private int endColumn; // end column + + /// <summary> + /// The line at which the text span starts. + /// </summary> + public int StartLine { get { return startLine; } } + + /// <summary> + /// The column at which the text span starts. + /// </summary> + public int StartColumn { get { return startColumn; } } + + /// <summary> + /// The line on which the text span ends. + /// </summary> + public int EndLine { get { return endLine; } } + + /// <summary> + /// The column of the first character + /// beyond the end of the text span. + /// </summary> + public int EndColumn { get { return endColumn; } } + + /// <summary> + /// Default no-arg constructor. + /// </summary> + public LexLocation() + { } + + /// <summary> + /// Constructor for text-span with given start and end. + /// </summary> + /// <param name="sl">start line</param> + /// <param name="sc">start column</param> + /// <param name="el">end line </param> + /// <param name="ec">end column</param> + public LexLocation(int sl, int sc, int el, int ec) + { startLine = sl; startColumn = sc; endLine = el; endColumn = ec; } + + /// <summary> + /// Create a text location which spans from the + /// start of "this" to the end of the argument "last" + /// </summary> + /// <param name="last">The last location in the result span</param> + /// <returns>The merged span</returns> + public LexLocation Merge(LexLocation last) + { return new LexLocation(this.startLine, this.startColumn, last.endLine, last.endColumn); } + + } + + /// <summary> + /// Abstract scanner class that GPPG expects its scanners to + /// extend. + /// </summary> + /// <typeparam name="TValue">Semantic value type YYSTYPE</typeparam> + /// <typeparam name="TSpan">Source location type YYLTYPE</typeparam> +#if EXPORT_GPPG + public abstract class AbstractScanner<TValue, TSpan> +#else + internal abstract class AbstractScanner<TValue, TSpan> +#endif + where TSpan : IMerge<TSpan> + { + /// <summary> + /// Lexical value optionally set by the scanner. The value + /// is of the %YYSTYPE type declared in the parser spec. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylval")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylval")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + // A field must be declared for this value of parametric type, + // since it may be instantiated by a value struct. If it were + // implemented as a property, machine generated code in derived + // types would not be able to select on the returned value. + public TValue yylval; // Lexical value: set by scanner + + /// <summary> + /// Current scanner location property. The value is of the + /// type declared by %YYLTYPE in the parser specification. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylloc")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylloc")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public virtual TSpan yylloc + { + get { return default(TSpan); } // Empty implementation allowing + set { /* skip */ } // yylloc to be ignored entirely. + } + + /// <summary> + /// Main call point for LEX-like scanners. Returns an int + /// corresponding to the token recognized by the scanner. + /// </summary> + /// <returns>An int corresponding to the token</returns> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public abstract int yylex(); + + /// <summary> + /// Traditional error reporting provided by LEX-like scanners + /// to their YACC-like clients. + /// </summary> + /// <param name="format">Message format string</param> + /// <param name="args">Optional array of args</param> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerror")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerror")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public virtual void yyerror(string format, params object[] args) { } + } + + /// <summary> + /// Encapsulated state for the parser. + /// Opaque to users, visible to the tool-generated code. + /// </summary> +#if EXPORT_GPPG + public class State +#else + internal class State +#endif + { + internal int number; + internal Dictionary<int, int> ParserTable; // Terminal -> ParseAction + internal Dictionary<int, int> Goto; // NonTerminal -> State; + internal int defaultAction; // = 0; // ParseAction + + /// <summary> + /// State transition data for this state. Pairs of elements of the + /// goto array associate symbol ordinals with next state indices. + /// The actions array is passed to another constructor. + /// </summary> + /// <param name="actions">The action list</param> + /// <param name="goToList">Next state data</param> + public State(int[] actions, int[] goToList) + : this(actions) + { + Goto = new Dictionary<int, int>(); + for (int i = 0; i < goToList.Length; i += 2) + Goto.Add(goToList[i], goToList[i + 1]); + } + + /// <summary> + /// Action data for this state. Pairs of elements of the + /// action array associate action ordinals with each of + /// those symbols that have actions in the current state. + /// </summary> + /// <param name="actions">The action array</param> + public State(int[] actions) + { + ParserTable = new Dictionary<int, int>(); + for (int i = 0; i < actions.Length; i += 2) + ParserTable.Add(actions[i], actions[i + 1]); + } + + /// <summary> + /// Set the default action for this state. + /// </summary> + /// <param name="defaultAction">Ordinal of the default action</param> + public State(int defaultAction) + { + this.defaultAction = defaultAction; + } + + /// <summary> + /// Set the default action and the state transition table. + /// </summary> + /// <param name="defaultAction">The default action</param> + /// <param name="goToList">Transitions from this state</param> + public State(int defaultAction, int[] goToList) + : this(defaultAction) + { + Goto = new Dictionary<int, int>(); + for (int i = 0; i < goToList.Length; i += 2) + Goto.Add(goToList[i], goToList[i + 1]); + } + } + + /// <summary> + /// Rule representation at runtime. + /// </summary> +#if EXPORT_GPPG + public class Rule +#else + internal class Rule +#endif + { + internal int LeftHandSide; // symbol + internal int[] RightHandSide; // symbols + + /// <summary> + /// Rule constructor. This holds the ordinal of + /// the left hand side symbol, and the list of + /// right hand side symbols, in lexical order. + /// </summary> + /// <param name="left">The LHS non-terminal</param> + /// <param name="right">The RHS symbols, in lexical order</param> + public Rule(int left, int[] right) + { + this.LeftHandSide = left; + this.RightHandSide = right; + } + } + + /// <summary> + /// Stack utility for the shift-reduce parser. + /// GPPG parsers have three instances: + /// (1) The parser state stack, T = QUT.Gppg.State, + /// (2) The semantic value stack, T = TValue, + /// (3) The location stack, T = TSpan. + /// </summary> + /// <typeparam name="T"></typeparam> +#if EXPORT_GPPG + public class PushdownPrefixState<T> +#else + internal class PushdownPrefixState<T> +#endif + { + // Note that we cannot use the BCL Stack<T> class + // here as derived types need to index into stacks. + // + private T[] array = new T[8]; + private int tos = 0; + + /// <summary> + /// Indexer for values of the stack below the top. + /// </summary> + /// <param name="index">index of the element, starting from the bottom</param> + /// <returns>the selected element</returns> + public T this[int index] { get { return array[index]; } } + + /// <summary> + /// The current depth of the stack. + /// </summary> + public int Depth { get { return tos; } } + + internal void Push(T value) + { + if (tos >= array.Length) + { + T[] newarray = new T[array.Length * 2]; + System.Array.Copy(array, newarray, tos); + array = newarray; + } + array[tos++] = value; + } + + internal T Pop() + { + T rslt = array[--tos]; + array[tos] = default(T); + return rslt; + } + + internal T TopElement() { return array[tos - 1]; } + + internal bool IsEmpty() { return tos == 0; } + } +} \ No newline at end of file diff --git a/Module7/SimpleLanguage2/SimpleLang2.csproj b/Module7/SimpleLanguage2/SimpleLang2.csproj new file mode 100644 index 0000000..e83a899 --- /dev/null +++ b/Module7/SimpleLanguage2/SimpleLang2.csproj @@ -0,0 +1,66 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>SimpleLang</RootNamespace> + <AssemblyName>SimpleLang</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Visitors\AssignCountVisitor.cs" /> + <Compile Include="Visitors\AutoVisitor.cs" /> + <Compile Include="Visitors\PrettyPrintVisitor.cs" /> + <Compile Include="Visitors\Visitor.cs" /> + <Compile Include="Main.cs" /> + <Compile Include="ParserHelper.cs" /> + <Compile Include="ProgramTree.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="ShiftReduceParserCode.cs" /> + <Compile Include="SimpleLex.cs" /> + <Compile Include="SimpleYacc.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project> \ No newline at end of file diff --git a/Module7/SimpleLanguage2/SimpleLang2.sln b/Module7/SimpleLanguage2/SimpleLang2.sln new file mode 100644 index 0000000..6983d32 --- /dev/null +++ b/Module7/SimpleLanguage2/SimpleLang2.sln @@ -0,0 +1,22 @@ +п»ї +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleLang2", "SimpleLang2.csproj", "{12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Debug|x86.ActiveCfg = Debug|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Debug|x86.Build.0 = Debug|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Release|x86.ActiveCfg = Release|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Module7/SimpleLanguage2/SimpleLex.cs b/Module7/SimpleLanguage2/SimpleLex.cs new file mode 100644 index 0000000..3658b77 --- /dev/null +++ b/Module7/SimpleLanguage2/SimpleLex.cs @@ -0,0 +1,1531 @@ +// +// This CSharp output file generated by Gardens Point LEX +// Version: 1.1.3.301 +// Machine: SSM +// DateTime: 19.08.2014 13:38:37 +// UserName: ????????? +// GPLEX input file <SimpleLex.lex> +// GPLEX frame file <embedded resource> +// +// Option settings: unicode, parser, minimize +// Option settings: classes, compressMap, compressNext, persistBuffer, embedbuffers +// Fallback code page: Target machine default +// + +// +// Experimental embedded frame +// Version 1.1.3 of 18-April-2010 +// +// +#define BACKUP +#define PERSIST + +using System; +using System.IO; +using System.Text; +using System.Globalization; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; + +using SimpleParser; +using QUT.Gppg; +using System.Linq; + +namespace SimpleScanner +{ + /// <summary> + /// Summary Canonical example of GPLEX automaton + /// </summary> + +#if STANDALONE + // + // These are the dummy declarations for stand-alone GPLEX applications + // normally these declarations would come from the parser. + // If you declare /noparser, or %option noparser then you get this. + // + + public enum Tokens + { + EOF = 0, maxParseToken = int.MaxValue + // must have at least these two, values are almost arbitrary + } + + public abstract class ScanBase + { + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + public abstract int yylex(); + + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yywrap")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yywrap")] + protected virtual bool yywrap() { return true; } + +#if BABEL + protected abstract int CurrentSc { get; set; } + // EolState is the 32-bit of state data persisted at + // the end of each line for Visual Studio colorization. + // The default is to return CurrentSc. You must override + // this if you want more complicated behavior. + public virtual int EolState { + get { return CurrentSc; } + set { CurrentSc = value; } + } + } + + public interface IColorScan + { + void SetSource(string source, int offset); + int GetNext(ref int state, out int start, out int end); +#endif // BABEL + } + +#endif // STANDALONE + + // If the compiler can't find the scanner base class maybe you + // need to run GPPG with the /gplex option, or GPLEX with /noparser +#if BABEL + public sealed partial class Scanner : ScanBase, IColorScan + { + private ScanBuff buffer; + int currentScOrd; // start condition ordinal + + protected override int CurrentSc + { + // The current start state is a property + // to try to avoid the user error of setting + // scState but forgetting to update the FSA + // start state "currentStart" + // + get { return currentScOrd; } // i.e. return YY_START; + set { currentScOrd = value; // i.e. BEGIN(value); + currentStart = startState[value]; } + } +#else // BABEL + public sealed partial class Scanner : ScanBase + { + private ScanBuff buffer; + int currentScOrd; // start condition ordinal +#endif // BABEL + + /// <summary> + /// The input buffer for this scanner. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public ScanBuff Buffer { get { return buffer; } } + + private static int GetMaxParseToken() { + System.Reflection.FieldInfo f = typeof(Tokens).GetField("maxParseToken"); + return (f == null ? int.MaxValue : (int)f.GetValue(null)); + } + + static int parserMax = GetMaxParseToken(); + + enum Result {accept, noMatch, contextFound}; + + const int maxAccept = 17; + const int initial = 18; + const int eofNum = 0; + const int goStart = -1; + const int INITIAL = 0; + +#region user code +#endregion user code + + int state; + int currentStart = startState[0]; + int code; // last code read + int cCol; // column number of code + int lNum; // current line number + // + // The following instance variables are used, among other + // things, for constructing the yylloc location objects. + // + int tokPos; // buffer position at start of token + int tokCol; // zero-based column number at start of token + int tokLin; // line number at start of token + int tokEPos; // buffer position at end of token + int tokECol; // column number at end of token + int tokELin; // line number at end of token + string tokTxt; // lazily constructed text of token +#if STACK + private Stack<int> scStack = new Stack<int>(); +#endif // STACK + +#region ScannerTables + struct Table { + public int min; public int rng; public int dflt; + public sbyte[] nxt; + public Table(int m, int x, int d, sbyte[] n) { + min = m; rng = x; dflt = d; nxt = n; + } + }; + + static int[] startState = new int[] {18, 0}; + +#region CompressedCharacterMap + // + // There are 15 equivalence classes + // There are 2 character sequence regions + // There are 1 tables, 123 entries + // There are 1 runs, 0 singletons + // Decision tree depth is 1 + // + static sbyte[] mapC0 = new sbyte[123] { +/* '\0' */ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 0, 14, 14, +/* '\x10' */ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +/* '\x20' */ 0, 14, 14, 14, 14, 14, 14, 14, 11, 12, 9, 8, 13, 7, 2, 10, +/* '0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 6, 14, 5, 14, 14, +/* '@' */ 14, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* 'P' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 14, 14, 14, 14, 3, +/* '`' */ 14, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* 'p' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; + + static sbyte MapC(int code) + { // '\0' <= code <= '\U0010FFFF' + if (code < 123) // '\0' <= code <= 'z' + return mapC0[code - 0]; + else // '{' <= code <= '\U0010FFFF' + return (sbyte)14; + } +#endregion + + static Table[] NxS = new Table[20] { +/* NxS[ 0] */ new Table(0, 0, 0, null), +/* NxS[ 1] */ new Table(1, 2, -1, new sbyte[] {1, 19}), +/* NxS[ 2] */ new Table(0, 0, -1, null), +/* NxS[ 3] */ new Table(1, 3, -1, new sbyte[] {3, -1, 3}), +/* NxS[ 4] */ new Table(5, 1, -1, new sbyte[] {16}), +/* NxS[ 5] */ new Table(0, 0, -1, null), +/* NxS[ 6] */ new Table(5, 1, -1, new sbyte[] {15}), +/* NxS[ 7] */ new Table(5, 1, -1, new sbyte[] {14}), +/* NxS[ 8] */ new Table(5, 1, -1, new sbyte[] {13}), +/* NxS[ 9] */ new Table(0, 0, -1, null), +/* NxS[ 10] */ new Table(0, 0, -1, null), +/* NxS[ 11] */ new Table(0, 0, -1, null), +/* NxS[ 12] */ new Table(0, 0, -1, null), +/* NxS[ 13] */ new Table(0, 0, -1, null), +/* NxS[ 14] */ new Table(0, 0, -1, null), +/* NxS[ 15] */ new Table(0, 0, -1, null), +/* NxS[ 16] */ new Table(0, 0, -1, null), +/* NxS[ 17] */ new Table(1, 1, -1, new sbyte[] {17}), +/* NxS[ 18] */ new Table(1, 14, -1, new sbyte[] {1, 2, 3, 4, 2, 5, + 6, 7, 8, 9, 10, 11, 12, 2}), +/* NxS[ 19] */ new Table(1, 1, -1, new sbyte[] {17}), + }; + +int NextState() { + if (code == ScanBuff.EndOfFile) + return eofNum; + else + unchecked { + int rslt; + int idx = MapC(code) - NxS[state].min; + if (idx < 0) idx += 15; + if ((uint)idx >= (uint)NxS[state].rng) rslt = NxS[state].dflt; + else rslt = NxS[state].nxt[idx]; + return rslt; + } +} + +#endregion + + +#if BACKUP + // ============================================================== + // == Nested struct used for backup in automata that do backup == + // ============================================================== + + struct Context // class used for automaton backup. + { + public int bPos; + public int rPos; // scanner.readPos saved value + public int cCol; + public int lNum; // Need this in case of backup over EOL. + public int state; + public int cChr; + } + + private Context ctx = new Context(); +#endif // BACKUP + + // ============================================================== + // ==== Nested struct to support input switching in scanners ==== + // ============================================================== + + struct BufferContext { + internal ScanBuff buffSv; + internal int chrSv; + internal int cColSv; + internal int lNumSv; + } + + // ============================================================== + // ===== Private methods to save and restore buffer contexts ==== + // ============================================================== + + /// <summary> + /// This method creates a buffer context record from + /// the current buffer object, together with some + /// scanner state values. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + BufferContext MkBuffCtx() + { + BufferContext rslt; + rslt.buffSv = this.buffer; + rslt.chrSv = this.code; + rslt.cColSv = this.cCol; + rslt.lNumSv = this.lNum; + return rslt; + } + + /// <summary> + /// This method restores the buffer value and allied + /// scanner state from the given context record value. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void RestoreBuffCtx(BufferContext value) + { + this.buffer = value.buffSv; + this.code = value.chrSv; + this.cCol = value.cColSv; + this.lNum = value.lNumSv; + } + // =================== End Nested classes ======================= + +#if !NOFILES + public Scanner(Stream file) { + SetSource(file, 0); // unicode option + } + + public Scanner(Stream file, string codepage) { + SetSource(file, CodePageHandling.GetCodePage(codepage)); + } + +#endif // !NOFILES + + public Scanner() { } + + private int readPos; + + void GetCode() + { + if (code == '\n') // This needs to be fixed for other conventions + // i.e. [\r\n\205\u2028\u2029] + { + cCol = -1; + lNum++; + } + readPos = buffer.Pos; + + // Now read new codepoint. + code = buffer.Read(); + if (code > ScanBuff.EndOfFile) + { +#if (!BYTEMODE) + if (code >= 0xD800 && code <= 0xDBFF) + { + int next = buffer.Read(); + if (next < 0xDC00 || next > 0xDFFF) + code = ScanBuff.UnicodeReplacementChar; + else + code = (0x10000 + (code & 0x3FF << 10) + (next & 0x3FF)); + } +#endif + cCol++; + } + } + + void MarkToken() + { +#if (!PERSIST) + buffer.Mark(); +#endif + tokPos = readPos; + tokLin = lNum; + tokCol = cCol; + } + + void MarkEnd() + { + tokTxt = null; + tokEPos = readPos; + tokELin = lNum; + tokECol = cCol; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int Peek() + { + int rslt, codeSv = code, cColSv = cCol, lNumSv = lNum, bPosSv = buffer.Pos; + GetCode(); rslt = code; + lNum = lNumSv; cCol = cColSv; code = codeSv; buffer.Pos = bPosSv; + return rslt; + } + + // ============================================================== + // ===== Initialization of string-based input buffers ==== + // ============================================================== + + /// <summary> + /// Create and initialize a StringBuff buffer object for this scanner + /// </summary> + /// <param name="source">the input string</param> + /// <param name="offset">starting offset in the string</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(string source, int offset) + { + this.buffer = ScanBuff.GetBuffer(source); + this.buffer.Pos = offset; + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } + +#if !NOFILES + // ================ LineBuffer Initialization =================== + + /// <summary> + /// Create and initialize a LineBuff buffer object for this scanner + /// </summary> + /// <param name="source">the list of input strings</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(IList<string> source) + { + this.buffer = ScanBuff.GetBuffer(source); + this.code = '\n'; // to initialize yyline, yycol and lineStart + this.lNum = 0; + GetCode(); + } + + // =============== StreamBuffer Initialization ================== + + /// <summary> + /// Create and initialize a StreamBuff buffer object for this scanner. + /// StreamBuff is buffer for 8-bit byte files. + /// </summary> + /// <param name="source">the input byte stream</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(Stream source) + { + this.buffer = ScanBuff.GetBuffer(source); + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } + +#if !BYTEMODE + // ================ TextBuffer Initialization =================== + + /// <summary> + /// Create and initialize a TextBuff buffer object for this scanner. + /// TextBuff is a buffer for encoded unicode files. + /// </summary> + /// <param name="source">the input text file</param> + /// <param name="fallbackCodePage">Code page to use if file has + /// no BOM. For 0, use machine default; for -1, 8-bit binary</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(Stream source, int fallbackCodePage) + { + this.buffer = ScanBuff.GetBuffer(source, fallbackCodePage); + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } +#endif // !BYTEMODE +#endif // !NOFILES + + // ============================================================== + +#if BABEL + // + // Get the next token for Visual Studio + // + // "state" is the inout mode variable that maintains scanner + // state between calls, using the EolState property. In principle, + // if the calls of EolState are costly set could be called once + // only per line, at the start; and get called only at the end + // of the line. This needs more infrastructure ... + // + public int GetNext(ref int state, out int start, out int end) + { + Tokens next; + int s, e; + s = state; // state at start + EolState = state; + next = (Tokens)Scan(); + state = EolState; + e = state; // state at end; + start = tokPos; + end = tokEPos - 1; // end is the index of last char. + return (int)next; + } +#endif // BABEL + + // ======== AbstractScanner<> Implementation ========= + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + public override int yylex() + { + // parserMax is set by reflecting on the Tokens + // enumeration. If maxParseToken is defined + // that is used, otherwise int.MaxValue is used. + int next; + do { next = Scan(); } while (next >= parserMax); + return next; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yypos { get { return tokPos; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yyline { get { return tokLin; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yycol { get { return tokCol; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yytext")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yytext")] + public string yytext + { + get + { + if (tokTxt == null) + tokTxt = buffer.GetString(tokPos, tokEPos); + return tokTxt; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void yyless(int n) + { + buffer.Pos = tokPos; + // Must read at least one char, so set before start. + cCol = tokCol - 1; + GetCode(); + // Now ensure that line counting is correct. + lNum = tokLin; + // And count the rest of the text. + for (int i = 0; i < n; i++) GetCode(); + MarkEnd(); + } + + // + // It would be nice to count backward in the text + // but it does not seem possible to re-establish + // the correct column counts except by going forward. + // + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void _yytrunc(int n) { yyless(yyleng - n); } + + // + // This is painful, but we no longer count + // codepoints. For the overwhelming majority + // of cases the single line code is fast, for + // the others, well, at least it is all in the + // buffer so no files are touched. Note that we + // can't use (tokEPos - tokPos) because of the + // possibility of surrogate pairs in the token. + // + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyleng")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyleng")] + public int yyleng + { + get { +#if BYTEMODE + return tokEPos - tokPos; +#else + if (tokELin == tokLin) + return tokECol - tokCol; + else { + int ch; + int count = 0; + int save = buffer.Pos; + buffer.Pos = tokPos; + do { + ch = buffer.Read(); + if (!char.IsHighSurrogate((char)ch)) count++; + } while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile); + buffer.Pos = save; + return count; + } +#endif // BYTEMODE + } + } + + // ============ methods available in actions ============== + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal int YY_START { + get { return currentScOrd; } + set { currentScOrd = value; + currentStart = startState[value]; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void BEGIN(int next) { + currentScOrd = next; + currentStart = startState[next]; + } + + // ============== The main tokenizer code ================= + + int Scan() + { + try { + for (; ; ) + { + int next; // next state to enter +#if BACKUP + Result rslt = Result.noMatch; +#endif // BACKUP +#if LEFTANCHORS + for (;;) + { + // Discard characters that do not start any pattern. + // Must check the left anchor condition after *every* GetCode! + state = ((cCol == 0) ? anchorState[currentScOrd] : currentStart); + if ((next = NextState()) != goStart) + break; // LOOP EXIT HERE... + GetCode(); + } + +#else // !LEFTANCHORS + state = currentStart; + while ((next = NextState()) == goStart) + // At this point, the current character has no + // transition from the current state. We discard + // the "no-match" char. In traditional LEX such + // characters are echoed to the console. + GetCode(); +#endif // LEFTANCHORS + // At last, a valid transition ... + MarkToken(); + state = next; + GetCode(); + + while ((next = NextState()) > eofNum) // Exit for goStart AND for eofNum +#if BACKUP + if (state <= maxAccept && next > maxAccept) // need to prepare backup data + { + // ctx is an object. The fields may be + // mutated by the call to Recurse2. + // On return the data in ctx is the + // *latest* accept state that was found. + + rslt = Recurse2(ref ctx, next); + if (rslt == Result.noMatch) + RestoreStateAndPos(ref ctx); + break; + } + else +#endif // BACKUP + { + state = next; + GetCode(); + } + if (state <= maxAccept) + { + MarkEnd(); +#region ActionSwitch +#pragma warning disable 162 + switch (state) + { + case eofNum: + if (yywrap()) + return (int)Tokens.EOF; + break; + case 1: +yylval.iVal = int.Parse(yytext); + return (int)Tokens.INUM; + break; + case 2: + case 4: +LexError(); + break; + case 3: +int res = ScannerHelper.GetIDToken(yytext); + if (res == (int)Tokens.ID) + yylval.sVal = yytext; + return res; + break; + case 5: +return (int)Tokens.SEMICOLON; + break; + case 6: +return (int)Tokens.MINUS; + break; + case 7: +return (int)Tokens.PLUS; + break; + case 8: +return (int)Tokens.MULT; + break; + case 9: +return (int)Tokens.DIV; + break; + case 10: +return (int)Tokens.LPAREN; + break; + case 11: +return (int)Tokens.RPAREN; + break; + case 12: +return (int)Tokens.COLUMN; + break; + case 13: +return (int)Tokens.ASSIGNMULT; + break; + case 14: +return (int)Tokens.ASSIGNPLUS; + break; + case 15: +return (int)Tokens.ASSIGNMINUS; + break; + case 16: +return (int)Tokens.ASSIGN; + break; + case 17: +yylval.dVal = double.Parse(yytext); + return (int)Tokens.RNUM; + break; + default: + break; + } +#pragma warning restore 162 +#endregion + } + } + } // end try + finally { +// User-specified epilog to scan() +yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); +// End, user-specified epilog + } // end finally + } + +#if BACKUP + Result Recurse2(ref Context ctx, int next) + { + // Assert: at entry "state" is an accept state AND + // NextState(state, code) != goStart AND + // NextState(state, code) is not an accept state. + // + SaveStateAndPos(ref ctx); + state = next; + GetCode(); + + while ((next = NextState()) > eofNum) + { + if (state <= maxAccept && next > maxAccept) // need to update backup data + SaveStateAndPos(ref ctx); + state = next; + if (state == eofNum) return Result.accept; + GetCode(); + } + return (state <= maxAccept ? Result.accept : Result.noMatch); + } + + void SaveStateAndPos(ref Context ctx) + { + ctx.bPos = buffer.Pos; + ctx.rPos = readPos; + ctx.cCol = cCol; + ctx.lNum = lNum; + ctx.state = state; + ctx.cChr = code; + } + + void RestoreStateAndPos(ref Context ctx) + { + buffer.Pos = ctx.bPos; + readPos = ctx.rPos; + cCol = ctx.cCol; + lNum = ctx.lNum; + state = ctx.state; + code = ctx.cChr; + } + +#endif // BACKUP + + // ============= End of the tokenizer code ================ + +#if STACK + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void yy_clear_stack() { scStack.Clear(); } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal int yy_top_state() { return scStack.Peek(); } + + internal void yy_push_state(int state) + { + scStack.Push(currentScOrd); + BEGIN(state); + } + + internal void yy_pop_state() + { + // Protect against input errors that pop too far ... + if (scStack.Count > 0) { + int newSc = scStack.Pop(); + BEGIN(newSc); + } // Otherwise leave stack unchanged. + } + #endif // STACK + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void ECHO() { Console.Out.Write(yytext); } + +#region UserCodeSection + +public override void yyerror(string format, params object[] args) // обработка синтаксических ошибок +{ + var ww = args.Skip(1).Cast<string>().ToArray(); + string errorMsg = string.Format("({0},{1}): Встречено {2}, а ожидалось {3}", yyline, yycol, args[0], string.Join(" или ", ww)); + throw new SyntaxException(errorMsg); +} + +public void LexError() +{ + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); + throw new LexException(errorMsg); +} + +class ScannerHelper +{ + private static Dictionary<string,int> keywords; + + static ScannerHelper() + { + keywords = new Dictionary<string,int>(); + keywords.Add("begin",(int)Tokens.BEGIN); + keywords.Add("end",(int)Tokens.END); + keywords.Add("cycle",(int)Tokens.CYCLE); + keywords.Add("write",(int)Tokens.WRITE); + keywords.Add("var",(int)Tokens.VAR); + } + public static int GetIDToken(string s) + { + if (keywords.ContainsKey(s.ToLower())) + return keywords[s]; + else + return (int)Tokens.ID; + } + +} + +#endregion + } // end class $Scanner + +// ============================================================== +// <auto-generated> +// This code automatically produced from an embedded resource. +// Do not edit this file, or it will become incompatible with +// the specification from which it was generated. +// </auto-generated> +// ============================================================== + +// Code copied from GPLEX embedded resource + [Serializable] + public class BufferException : Exception + { + public BufferException() { } + public BufferException(string message) : base(message) { } + public BufferException(string message, Exception innerException) + : base(message, innerException) { } + protected BufferException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + } + + public abstract class ScanBuff + { + private string fileNm; + + public const int EndOfFile = -1; + public const int UnicodeReplacementChar = 0xFFFD; + + public bool IsFile { get { return (fileNm != null); } } + public string FileName { get { return fileNm; } set { fileNm = value; } } + + public abstract int Pos { get; set; } + public abstract int Read(); + public virtual void Mark() { } + + public abstract string GetString(int begin, int limit); + + public static ScanBuff GetBuffer(string source) + { + return new StringBuffer(source); + } + + public static ScanBuff GetBuffer(IList<string> source) + { + return new LineBuffer(source); + } + + public static ScanBuff GetBuffer(Stream source) + { + return new BuildBuffer(source); + } + +#if (!BYTEMODE) + public static ScanBuff GetBuffer(Stream source, int fallbackCodePage) + { + return new BuildBuffer(source, fallbackCodePage); + } +#endif + } + + #region Buffer classes + + // ============================================================== + // ===== Definitions for various ScanBuff derived classes ==== + // ============================================================== + // =============== String input ================ + // ============================================================== + + /// <summary> + /// This class reads characters from a single string as + /// required, for example, by Visual Studio language services + /// </summary> + sealed class StringBuffer : ScanBuff + { + string str; // input buffer + int bPos; // current position in buffer + int sLen; + + public StringBuffer(string source) + { + this.str = source; + this.sLen = source.Length; + this.FileName = null; + } + + public override int Read() + { + if (bPos < sLen) return str[bPos++]; + else if (bPos == sLen) { bPos++; return '\n'; } // one strike, see new line + else { bPos++; return EndOfFile; } // two strikes and you're out! + } + + public override string GetString(int begin, int limit) + { + // "limit" can be greater than sLen with the BABEL + // option set. Read returns a "virtual" EOL if + // an attempt is made to read past the end of the + // string buffer. Without the guard any attempt + // to fetch yytext for a token that includes the + // EOL will throw an index exception. + if (limit > sLen) limit = sLen; + if (limit <= begin) return ""; + else return str.Substring(begin, limit - begin); + } + + public override int Pos + { + get { return bPos; } + set { bPos = value; } + } + + public override string ToString() { return "StringBuffer"; } + } + + // ============================================================== + // The LineBuff class contributed by Nigel Horspool, + // nigelh@cs.uvic.cs + // ============================================================== + + sealed class LineBuffer : ScanBuff + { + IList<string> line; // list of source lines from a file + int numLines; // number of strings in line list + string curLine; // current line in that list + int cLine; // index of current line in the list + int curLen; // length of current line + int curLineStart; // position of line start in whole file + int curLineEnd; // position of line end in whole file + int maxPos; // max position ever visited in whole file + int cPos; // ordinal number of code in source + + // Constructed from a list of strings, one per source line. + // The lines have had trailing '\n' characters removed. + public LineBuffer(IList<string> lineList) + { + line = lineList; + numLines = line.Count; + cPos = curLineStart = 0; + curLine = (numLines > 0 ? line[0] : ""); + maxPos = curLineEnd = curLen = curLine.Length; + cLine = 1; + FileName = null; + } + + public override int Read() + { + if (cPos < curLineEnd) + return curLine[cPos++ - curLineStart]; + if (cPos++ == curLineEnd) + return '\n'; + if (cLine >= numLines) + return EndOfFile; + curLine = line[cLine]; + curLen = curLine.Length; + curLineStart = curLineEnd + 1; + curLineEnd = curLineStart + curLen; + if (curLineEnd > maxPos) + maxPos = curLineEnd; + cLine++; + return curLen > 0 ? curLine[0] : '\n'; + } + + // To speed up searches for the line containing a position + private int cachedPosition; + private int cachedIxdex; + private int cachedLineStart; + + // Given a position pos within the entire source, the results are + // ix -- the index of the containing line + // lstart -- the position of the first character on that line + private void findIndex(int pos, out int ix, out int lstart) + { + if (pos >= cachedPosition) + { + ix = cachedIxdex; lstart = cachedLineStart; + } + else + { + ix = lstart = 0; + } + for (; ; ) + { + int len = line[ix].Length + 1; + if (pos < lstart + len) break; + lstart += len; + ix++; + } + cachedPosition = pos; + cachedIxdex = ix; + cachedLineStart = lstart; + } + + public override string GetString(int begin, int limit) + { + if (begin >= maxPos || limit <= begin) return ""; + int endIx, begIx, endLineStart, begLineStart; + findIndex(begin, out begIx, out begLineStart); + int begCol = begin - begLineStart; + findIndex(limit, out endIx, out endLineStart); + int endCol = limit - endLineStart; + string s = line[begIx]; + if (begIx == endIx) + { + // the usual case, substring all on one line + return (endCol <= s.Length) ? + s.Substring(begCol, endCol - begCol) + : s.Substring(begCol) + "\n"; + } + // the string spans multiple lines, yuk! + StringBuilder sb = new StringBuilder(); + if (begCol < s.Length) + sb.Append(s.Substring(begCol)); + for (; ; ) + { + sb.Append("\n"); + s = line[++begIx]; + if (begIx >= endIx) break; + sb.Append(s); + } + if (endCol <= s.Length) + { + sb.Append(s.Substring(0, endCol)); + } + else + { + sb.Append(s); + sb.Append("\n"); + } + return sb.ToString(); + } + + public override int Pos + { + get { return cPos; } + set + { + cPos = value; + findIndex(cPos, out cLine, out curLineStart); + curLine = line[cLine]; + curLineEnd = curLineStart + curLine.Length; + } + } + + public override string ToString() { return "LineBuffer"; } + } + + + // ============================================================== + // ===== class BuildBuff : for unicode text files ======== + // ============================================================== + + class BuildBuffer : ScanBuff + { + // Double buffer for char stream. + class BufferElement + { + StringBuilder bldr = new StringBuilder(); + StringBuilder next = new StringBuilder(); + int minIx; + int maxIx; + int brkIx; + bool appendToNext; + + internal BufferElement() { } + + internal int MaxIndex { get { return maxIx; } } + // internal int MinIndex { get { return minIx; } } + + internal char this[int index] + { + get + { + if (index < minIx || index >= maxIx) + throw new BufferException("Index was outside data buffer"); + else if (index < brkIx) + return bldr[index - minIx]; + else + return next[index - brkIx]; + } + } + + internal void Append(char[] block, int count) + { + maxIx += count; + if (appendToNext) + this.next.Append(block, 0, count); + else + { + this.bldr.Append(block, 0, count); + brkIx = maxIx; + appendToNext = true; + } + } + + internal string GetString(int start, int limit) + { + if (limit <= start) + return ""; + if (start >= minIx && limit <= maxIx) + if (limit < brkIx) // String entirely in bldr builder + return bldr.ToString(start - minIx, limit - start); + else if (start >= brkIx) // String entirely in next builder + return next.ToString(start - brkIx, limit - start); + else // Must do a string-concatenation + return + bldr.ToString(start - minIx, brkIx - start) + + next.ToString(0, limit - brkIx); + else + throw new BufferException("String was outside data buffer"); + } + + internal void Mark(int limit) + { + if (limit > brkIx + 16) // Rotate blocks + { + StringBuilder temp = bldr; + bldr = next; + next = temp; + next.Length = 0; + minIx = brkIx; + brkIx = maxIx; + } + } + } + + BufferElement data = new BufferElement(); + + int bPos; // Postion index in the StringBuilder + BlockReader NextBlk; // Delegate that serves char-arrays; + + private string EncodingName + { + get + { + StreamReader rdr = NextBlk.Target as StreamReader; + return (rdr == null ? "raw-bytes" : rdr.CurrentEncoding.BodyName); + } + } + + public BuildBuffer(Stream stream) + { + FileStream fStrm = (stream as FileStream); + if (fStrm != null) FileName = fStrm.Name; + NextBlk = BlockReaderFactory.Raw(stream); + } + +#if (!BYTEMODE) + public BuildBuffer(Stream stream, int fallbackCodePage) + { + FileStream fStrm = (stream as FileStream); + if (fStrm != null) FileName = fStrm.Name; + NextBlk = BlockReaderFactory.Get(stream, fallbackCodePage); + } +#endif + + /// <summary> + /// Marks a conservative lower bound for the buffer, + /// allowing space to be reclaimed. If an application + /// needs to call GetString at arbitrary past locations + /// in the input stream, Mark() is not called. + /// </summary> + public override void Mark() { data.Mark(bPos - 2); } + + public override int Pos + { + get { return bPos; } + set { bPos = value; } + } + + + /// <summary> + /// Read returns the ordinal number of the next char, or + /// EOF (-1) for an end of stream. Note that the next + /// code point may require *two* calls of Read(). + /// </summary> + /// <returns></returns> + public override int Read() + { + // + // Characters at positions + // [data.offset, data.offset + data.bldr.Length) + // are available in data.bldr. + // + if (bPos < data.MaxIndex) + { + // ch0 cannot be EOF + return (int)data[bPos++]; + } + else // Read from underlying stream + { + // Experimental code, blocks of page size + char[] chrs = new char[4096]; + int count = NextBlk(chrs, 0, 4096); + if (count == 0) + return EndOfFile; + else + { + data.Append(chrs, count); + return (int)data[bPos++]; + } + } + } + + public override string GetString(int begin, int limit) + { + return data.GetString(begin, limit); + } + + public override string ToString() + { + return "StringBuilder buffer, encoding: " + this.EncodingName; + } + } + + // =============== End ScanBuff-derived classes ================== + + public delegate int BlockReader(char[] block, int index, int number); + + // A delegate factory, serving up a delegate that + // reads a block of characters from the underlying + // encoded stream, via a StreamReader object. + // + public static class BlockReaderFactory + { + public static BlockReader Raw(Stream stream) + { + return delegate(char[] block, int index, int number) + { + byte[] b = new byte[number]; + int count = stream.Read(b, 0, number); + int i = 0; + int j = index; + for (; i < count; i++, j++) + block[j] = (char)b[i]; + return count; + }; + } + +#if (!BYTEMODE) + public static BlockReader Get(Stream stream, int fallbackCodePage) + { + Encoding encoding; + int preamble = Preamble(stream); + + if (preamble != 0) // There is a valid BOM here! + encoding = Encoding.GetEncoding(preamble); + else if (fallbackCodePage == -1) // Fallback is "raw" bytes + return Raw(stream); + else if (fallbackCodePage != -2) // Anything but "guess" + encoding = Encoding.GetEncoding(fallbackCodePage); + else // This is the "guess" option + { + int guess = new Guesser(stream).GuessCodePage(); + stream.Seek(0, SeekOrigin.Begin); + if (guess == -1) // ==> this is a 7-bit file + encoding = Encoding.ASCII; + else if (guess == 65001) + encoding = Encoding.UTF8; + else // ==> use the machine default + encoding = Encoding.Default; + } + StreamReader reader = new StreamReader(stream, encoding); + return reader.Read; + } + + static int Preamble(Stream stream) + { + int b0 = stream.ReadByte(); + int b1 = stream.ReadByte(); + + if (b0 == 0xfe && b1 == 0xff) + return 1201; // UTF16BE + if (b0 == 0xff && b1 == 0xfe) + return 1200; // UTF16LE + + int b2 = stream.ReadByte(); + if (b0 == 0xef && b1 == 0xbb && b2 == 0xbf) + return 65001; // UTF8 + // + // There is no unicode preamble, so we + // return denoter for the machine default. + // + stream.Seek(0, SeekOrigin.Begin); + return 0; + } +#endif // !BYTEMODE + } + #endregion Buffer classes + + // ============================================================== + // ============ class CodePageHandling ============= + // ============================================================== + + public static class CodePageHandling + { + public static int GetCodePage(string option) + { + string command = option.ToUpperInvariant(); + if (command.StartsWith("CodePage:", StringComparison.OrdinalIgnoreCase)) + command = command.Substring(9); + try + { + if (command.Equals("RAW")) + return -1; + else if (command.Equals("GUESS")) + return -2; + else if (command.Equals("DEFAULT")) + return 0; + else if (char.IsDigit(command[0])) + return int.Parse(command, CultureInfo.InvariantCulture); + else + { + Encoding enc = Encoding.GetEncoding(command); + return enc.CodePage; + } + } + catch (FormatException) + { + Console.Error.WriteLine( + "Invalid format \"{0}\", using machine default", option); + } + catch (ArgumentException) + { + Console.Error.WriteLine( + "Unknown code page \"{0}\", using machine default", option); + } + return 0; + } + } +#region guesser +#if (!BYTEMODE) + // ============================================================== + // ============ Encoding Guesser ============= + // ============================================================== + + /// <summary> + /// This class provides a simple finite state automaton that + /// scans the file looking for (1) valid UTF-8 byte patterns, + /// (2) bytes >= 0x80 which are not part of a UTF-8 sequence. + /// The method then guesses whether it is UTF-8 or maybe some + /// local machine default encoding. This works well for the + /// various Latin encodings. + /// </summary> + internal class Guesser + { + ScanBuff buffer; + + public int GuessCodePage() { return Scan(); } + + const int maxAccept = 10; + const int initial = 0; + const int eofNum = 0; + const int goStart = -1; + const int INITIAL = 0; + const int EndToken = 0; + + #region user code + /* + * Reads the bytes of a file to determine if it is + * UTF-8 or a single-byte code page file. + */ + public long utfX; + public long uppr; + #endregion user code + + int state; + int currentStart = startState[0]; + int code; + + #region ScannerTables + static int[] startState = new int[] { 11, 0 }; + + #region CharacterMap + static sbyte[] map = new sbyte[256] { +/* '\0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x10' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x20' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '@' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 'P' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '`' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 'p' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x80' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\x90' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xA0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xB0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xC0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* '\xD0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* '\xE0' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* '\xF0' */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5 }; + #endregion + + static sbyte[][] nextState = new sbyte[][] { + new sbyte[] {0, 0, 0, 0, 0, 0}, + new sbyte[] {-1, -1, 10, -1, -1, -1}, + new sbyte[] {-1, -1, -1, -1, -1, -1}, + new sbyte[] {-1, -1, 8, -1, -1, -1}, + new sbyte[] {-1, -1, 5, -1, -1, -1}, + new sbyte[] {-1, -1, 6, -1, -1, -1}, + new sbyte[] {-1, -1, 7, -1, -1, -1}, + null, + new sbyte[] {-1, -1, 9, -1, -1, -1}, + null, + null, + new sbyte[] {-1, 1, 2, 3, 4, 2} + }; + + + [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + // Reason for suppression: cannot have self-reference in array initializer. + static Guesser() + { + nextState[7] = nextState[2]; + nextState[9] = nextState[2]; + nextState[10] = nextState[2]; + } + + int NextState() + { + if (code == ScanBuff.EndOfFile) + return eofNum; + else + return nextState[state][map[code]]; + } + #endregion + + public Guesser(System.IO.Stream file) { SetSource(file); } + + public void SetSource(System.IO.Stream source) + { + this.buffer = new BuildBuffer(source); + code = buffer.Read(); + } + + int Scan() + { + for (; ; ) + { + int next; + state = currentStart; + while ((next = NextState()) == goStart) + code = buffer.Read(); + + state = next; + code = buffer.Read(); + + while ((next = NextState()) > eofNum) + { + state = next; + code = buffer.Read(); + } + if (state <= maxAccept) + { + #region ActionSwitch +#pragma warning disable 162 + switch (state) + { + case eofNum: + switch (currentStart) + { + case 11: + if (utfX == 0 && uppr == 0) return -1; /* raw ascii */ + else if (uppr * 10 > utfX) return 0; /* default code page */ + else return 65001; /* UTF-8 encoding */ + break; + } + return EndToken; + case 1: // Recognized '{Upper128}', Shortest string "\xC0" + case 2: // Recognized '{Upper128}', Shortest string "\x80" + case 3: // Recognized '{Upper128}', Shortest string "\xE0" + case 4: // Recognized '{Upper128}', Shortest string "\xF0" + uppr++; + break; + case 5: // Recognized '{Utf8pfx4}{Utf8cont}', Shortest string "\xF0\x80" + uppr += 2; + break; + case 6: // Recognized '{Utf8pfx4}{Utf8cont}{2}', Shortest string "\xF0\x80\x80" + uppr += 3; + break; + case 7: // Recognized '{Utf8pfx4}{Utf8cont}{3}', Shortest string "\xF0\x80\x80\x80" + utfX += 3; + break; + case 8: // Recognized '{Utf8pfx3}{Utf8cont}', Shortest string "\xE0\x80" + uppr += 2; + break; + case 9: // Recognized '{Utf8pfx3}{Utf8cont}{2}', Shortest string "\xE0\x80\x80" + utfX += 2; + break; + case 10: // Recognized '{Utf8pfx2}{Utf8cont}', Shortest string "\xC0\x80" + utfX++; + break; + default: + break; + } +#pragma warning restore 162 + #endregion + } + } + } + } // end class Guesser + +#endif // !BYTEMODE +#endregion + +// End of code copied from embedded resource + +} // end namespace diff --git a/Module7/SimpleLanguage2/SimpleLex.lex b/Module7/SimpleLanguage2/SimpleLex.lex new file mode 100644 index 0000000..00dfa12 --- /dev/null +++ b/Module7/SimpleLanguage2/SimpleLex.lex @@ -0,0 +1,90 @@ +%using SimpleParser; +%using QUT.Gppg; +%using System.Linq; + +%namespace SimpleScanner + +Alpha [a-zA-Z_] +Digit [0-9] +AlphaDigit {Alpha}|{Digit} +INTNUM {Digit}+ +REALNUM {INTNUM}\.{INTNUM} +ID {Alpha}{AlphaDigit}* + +%% + +{INTNUM} { + yylval.iVal = int.Parse(yytext); + return (int)Tokens.INUM; +} + +{REALNUM} { + yylval.dVal = double.Parse(yytext); + return (int)Tokens.RNUM; +} + +{ID} { + int res = ScannerHelper.GetIDToken(yytext); + if (res == (int)Tokens.ID) + yylval.sVal = yytext; + return res; +} + +":=" { return (int)Tokens.ASSIGN; } +";" { return (int)Tokens.SEMICOLON; } +"-=" { return (int)Tokens.ASSIGNMINUS; } +"+=" { return (int)Tokens.ASSIGNPLUS; } +"*=" { return (int)Tokens.ASSIGNMULT; } +"+" { return (int)Tokens.PLUS; } +"-" { return (int)Tokens.MINUS; } +"*" { return (int)Tokens.MULT; } +"/" { return (int)Tokens.DIV; } +"(" { return (int)Tokens.LPAREN; } +")" { return (int)Tokens.RPAREN; } +"," { return (int)Tokens.COLUMN; } + +[^ \r\n] { + LexError(); +} + +%{ + yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); +%} + +%% + +public override void yyerror(string format, params object[] args) // обработка синтаксических ошибок +{ + var ww = args.Skip(1).Cast<string>().ToArray(); + string errorMsg = string.Format("({0},{1}): Встречено {2}, а ожидалось {3}", yyline, yycol, args[0], string.Join(" или ", ww)); + throw new SyntaxException(errorMsg); +} + +public void LexError() +{ + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); + throw new LexException(errorMsg); +} + +class ScannerHelper +{ + private static Dictionary<string,int> keywords; + + static ScannerHelper() + { + keywords = new Dictionary<string,int>(); + keywords.Add("begin",(int)Tokens.BEGIN); + keywords.Add("end",(int)Tokens.END); + keywords.Add("cycle",(int)Tokens.CYCLE); + keywords.Add("write",(int)Tokens.WRITE); + keywords.Add("var",(int)Tokens.VAR); + } + public static int GetIDToken(string s) + { + if (keywords.ContainsKey(s.ToLower())) + return keywords[s]; + else + return (int)Tokens.ID; + } + +} diff --git a/Module7/SimpleLanguage2/SimpleYacc.cs b/Module7/SimpleLanguage2/SimpleYacc.cs new file mode 100644 index 0000000..10d52e6 --- /dev/null +++ b/Module7/SimpleLanguage2/SimpleYacc.cs @@ -0,0 +1,274 @@ +// This code was generated by the Gardens Point Parser Generator +// Copyright (c) Wayne Kelly, QUT 2005-2010 +// (see accompanying GPPGcopyright.rtf) + +// GPPG version 1.3.6 +// Machine: SSM +// DateTime: 19.08.2014 13:38:37 +// UserName: ????????? +// Input file <SimpleYacc.y> + +// options: no-lines gplex + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using QUT.Gppg; +using System.IO; +using ProgramTree; + +namespace SimpleParser +{ +public enum Tokens { + error=1,EOF=2,BEGIN=3,END=4,CYCLE=5,ASSIGN=6, + ASSIGNPLUS=7,ASSIGNMINUS=8,ASSIGNMULT=9,SEMICOLON=10,WRITE=11,VAR=12, + PLUS=13,MINUS=14,MULT=15,DIV=16,LPAREN=17,RPAREN=18, + COLUMN=19,INUM=20,RNUM=21,ID=22}; + +public struct ValueType +{ + public double dVal; + public int iVal; + public string sVal; + public Node nVal; + public ExprNode eVal; + public StatementNode stVal; + public BlockNode blVal; + } +// Abstract base class for GPLEX scanners +public abstract class ScanBase : AbstractScanner<ValueType,LexLocation> { + private LexLocation __yylloc = new LexLocation(); + public override LexLocation yylloc { get { return __yylloc; } set { __yylloc = value; } } + protected virtual bool yywrap() { return true; } +} + +public class Parser: ShiftReduceParser<ValueType, LexLocation> +{ + // Verbatim content from SimpleYacc.y +// Эти объявления добавляются в класс GPPGParser, представляющий собой парсер, генерируемый системой gppg + public BlockNode root; // Корневой узел синтаксического дерева + public Parser(AbstractScanner<ValueType, LexLocation> scanner) : base(scanner) { } + private bool InDefSect = false; + // End verbatim content from SimpleYacc.y + +#pragma warning disable 649 + private static Dictionary<int, string> aliasses; +#pragma warning restore 649 + private static Rule[] rules = new Rule[30]; + private static State[] states = new State[48]; + private static string[] nonTerms = new string[] { + "progr", "expr", "ident", "T", "F", "statement", "assign", "block", "cycle", + "write", "empty", "var", "varlist", "stlist", "$accept", "Anon@1", }; + + static Parser() { + states[0] = new State(new int[]{3,4},new int[]{-1,1,-8,3}); + states[1] = new State(new int[]{2,2}); + states[2] = new State(-1); + states[3] = new State(-2); + states[4] = new State(new int[]{22,18,3,4,5,31,11,35,12,40,4,-11,10,-11},new int[]{-14,5,-6,47,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46}); + states[5] = new State(new int[]{4,6,10,7}); + states[6] = new State(-23); + states[7] = new State(new int[]{22,18,3,4,5,31,11,35,12,40,4,-11,10,-11},new int[]{-6,8,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46}); + states[8] = new State(-4); + states[9] = new State(-5); + states[10] = new State(new int[]{6,11}); + states[11] = new State(new int[]{22,18,20,19,17,20},new int[]{-2,12,-4,28,-5,27,-3,17}); + states[12] = new State(new int[]{13,13,14,23,4,-13,10,-13}); + states[13] = new State(new int[]{22,18,20,19,17,20},new int[]{-4,14,-5,27,-3,17}); + states[14] = new State(new int[]{15,15,16,25,13,-14,14,-14,4,-14,10,-14,18,-14,22,-14,3,-14,5,-14,11,-14,12,-14}); + states[15] = new State(new int[]{22,18,20,19,17,20},new int[]{-5,16,-3,17}); + states[16] = new State(-17); + states[17] = new State(-20); + states[18] = new State(-12); + states[19] = new State(-21); + states[20] = new State(new int[]{22,18,20,19,17,20},new int[]{-2,21,-4,28,-5,27,-3,17}); + states[21] = new State(new int[]{18,22,13,13,14,23}); + states[22] = new State(-22); + states[23] = new State(new int[]{22,18,20,19,17,20},new int[]{-4,24,-5,27,-3,17}); + states[24] = new State(new int[]{15,15,16,25,13,-15,14,-15,4,-15,10,-15,18,-15,22,-15,3,-15,5,-15,11,-15,12,-15}); + states[25] = new State(new int[]{22,18,20,19,17,20},new int[]{-5,26,-3,17}); + states[26] = new State(-18); + states[27] = new State(-19); + states[28] = new State(new int[]{15,15,16,25,13,-16,14,-16,4,-16,10,-16,18,-16,22,-16,3,-16,5,-16,11,-16,12,-16}); + states[29] = new State(-6); + states[30] = new State(-7); + states[31] = new State(new int[]{22,18,20,19,17,20},new int[]{-2,32,-4,28,-5,27,-3,17}); + states[32] = new State(new int[]{13,13,14,23,22,18,3,4,5,31,11,35,12,40,4,-11,10,-11},new int[]{-6,33,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46}); + states[33] = new State(-24); + states[34] = new State(-8); + states[35] = new State(new int[]{17,36}); + states[36] = new State(new int[]{22,18,20,19,17,20},new int[]{-2,37,-4,28,-5,27,-3,17}); + states[37] = new State(new int[]{18,38,13,13,14,23}); + states[38] = new State(-25); + states[39] = new State(-9); + states[40] = new State(-26,new int[]{-16,41}); + states[41] = new State(new int[]{22,18},new int[]{-13,42,-3,45}); + states[42] = new State(new int[]{19,43,4,-27,10,-27}); + states[43] = new State(new int[]{22,18},new int[]{-3,44}); + states[44] = new State(-29); + states[45] = new State(-28); + states[46] = new State(-10); + states[47] = new State(-3); + + rules[1] = new Rule(-15, new int[]{-1,2}); + rules[2] = new Rule(-1, new int[]{-8}); + rules[3] = new Rule(-14, new int[]{-6}); + rules[4] = new Rule(-14, new int[]{-14,10,-6}); + rules[5] = new Rule(-6, new int[]{-7}); + rules[6] = new Rule(-6, new int[]{-8}); + rules[7] = new Rule(-6, new int[]{-9}); + rules[8] = new Rule(-6, new int[]{-10}); + rules[9] = new Rule(-6, new int[]{-12}); + rules[10] = new Rule(-6, new int[]{-11}); + rules[11] = new Rule(-11, new int[]{}); + rules[12] = new Rule(-3, new int[]{22}); + rules[13] = new Rule(-7, new int[]{-3,6,-2}); + rules[14] = new Rule(-2, new int[]{-2,13,-4}); + rules[15] = new Rule(-2, new int[]{-2,14,-4}); + rules[16] = new Rule(-2, new int[]{-4}); + rules[17] = new Rule(-4, new int[]{-4,15,-5}); + rules[18] = new Rule(-4, new int[]{-4,16,-5}); + rules[19] = new Rule(-4, new int[]{-5}); + rules[20] = new Rule(-5, new int[]{-3}); + rules[21] = new Rule(-5, new int[]{20}); + rules[22] = new Rule(-5, new int[]{17,-2,18}); + rules[23] = new Rule(-8, new int[]{3,-14,4}); + rules[24] = new Rule(-9, new int[]{5,-2,-6}); + rules[25] = new Rule(-10, new int[]{11,17,-2,18}); + rules[26] = new Rule(-16, new int[]{}); + rules[27] = new Rule(-12, new int[]{12,-16,-13}); + rules[28] = new Rule(-13, new int[]{-3}); + rules[29] = new Rule(-13, new int[]{-13,19,-3}); + } + + protected override void Initialize() { + this.InitSpecialTokens((int)Tokens.error, (int)Tokens.EOF); + this.InitStates(states); + this.InitRules(rules); + this.InitNonTerminals(nonTerms); + } + + protected override void DoAction(int action) + { + switch (action) + { + case 2: // progr -> block +{ root = ValueStack[ValueStack.Depth-1].blVal; } + break; + case 3: // stlist -> statement +{ + CurrentSemanticValue.blVal = new BlockNode(ValueStack[ValueStack.Depth-1].stVal); + } + break; + case 4: // stlist -> stlist, SEMICOLON, statement +{ + ValueStack[ValueStack.Depth-3].blVal.Add(ValueStack[ValueStack.Depth-1].stVal); + CurrentSemanticValue.blVal = ValueStack[ValueStack.Depth-3].blVal; + } + break; + case 5: // statement -> assign +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 6: // statement -> block +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].blVal; } + break; + case 7: // statement -> cycle +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 8: // statement -> write +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 9: // statement -> var +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 10: // statement -> empty +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 11: // empty -> /* empty */ +{ CurrentSemanticValue.stVal = new EmptyNode(); } + break; + case 12: // ident -> ID +{ + if (!InDefSect) + if (!SymbolTable.vars.ContainsKey(ValueStack[ValueStack.Depth-1].sVal)) + throw new Exception("("+LocationStack[LocationStack.Depth-1].StartLine+","+LocationStack[LocationStack.Depth-1].StartColumn+"): Переменная "+ValueStack[ValueStack.Depth-1].sVal+" не описана"); + CurrentSemanticValue.eVal = new IdNode(ValueStack[ValueStack.Depth-1].sVal); + } + break; + case 13: // assign -> ident, ASSIGN, expr +{ CurrentSemanticValue.stVal = new AssignNode(ValueStack[ValueStack.Depth-3].eVal as IdNode, ValueStack[ValueStack.Depth-1].eVal); } + break; + case 14: // expr -> expr, PLUS, T +{ CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'+'); } + break; + case 15: // expr -> expr, MINUS, T +{ CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'-'); } + break; + case 16: // expr -> T +{ CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal; } + break; + case 17: // T -> T, MULT, F +{ CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'*'); } + break; + case 18: // T -> T, DIV, F +{ CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'/'); } + break; + case 19: // T -> F +{ CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal; } + break; + case 20: // F -> ident +{ CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal as IdNode; } + break; + case 21: // F -> INUM +{ CurrentSemanticValue.eVal = new IntNumNode(ValueStack[ValueStack.Depth-1].iVal); } + break; + case 22: // F -> LPAREN, expr, RPAREN +{ CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-2].eVal; } + break; + case 23: // block -> BEGIN, stlist, END +{ CurrentSemanticValue.blVal = ValueStack[ValueStack.Depth-2].blVal; } + break; + case 24: // cycle -> CYCLE, expr, statement +{ CurrentSemanticValue.stVal = new CycleNode(ValueStack[ValueStack.Depth-2].eVal,ValueStack[ValueStack.Depth-1].stVal); } + break; + case 25: // write -> WRITE, LPAREN, expr, RPAREN +{ CurrentSemanticValue.stVal = new WriteNode(ValueStack[ValueStack.Depth-2].eVal); } + break; + case 26: // Anon@1 -> /* empty */ +{ InDefSect = true; } + break; + case 27: // var -> VAR, Anon@1, varlist +{ + foreach (var v in (ValueStack[ValueStack.Depth-1].stVal as VarDefNode).vars) + SymbolTable.NewVarDef(v.Name, type.tint); + InDefSect = false; + } + break; + case 28: // varlist -> ident +{ + CurrentSemanticValue.stVal = new VarDefNode(ValueStack[ValueStack.Depth-1].eVal as IdNode); + } + break; + case 29: // varlist -> varlist, COLUMN, ident +{ + (ValueStack[ValueStack.Depth-3].stVal as VarDefNode).Add(ValueStack[ValueStack.Depth-1].eVal as IdNode); + CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-3].stVal; + } + break; + } + } + + protected override string TerminalToString(int terminal) + { + if (aliasses != null && aliasses.ContainsKey(terminal)) + return aliasses[terminal]; + else if (((Tokens)terminal).ToString() != terminal.ToString(CultureInfo.InvariantCulture)) + return ((Tokens)terminal).ToString(); + else + return CharToString((char)terminal); + } + + +} +} diff --git a/Module7/SimpleLanguage2/SimpleYacc.lst b/Module7/SimpleLanguage2/SimpleYacc.lst new file mode 100644 index 0000000..2de6038 --- /dev/null +++ b/Module7/SimpleLanguage2/SimpleYacc.lst @@ -0,0 +1,139 @@ + +// ========================================================================== +// GPPG error listing for yacc source file <SimpleYacc.y> +// ========================================================================== +// Version: 1.3.6 +// Machine: SSM +// DateTime: 19.08.2014 13:28:35 +// UserName: Станислав +// ========================================================================== + + +%{ +// ГќГІГЁ îáúÿâëåГГЁГї äîáà âëÿþòñÿ Гў êëà ññ GPPGParser, ïðåäñòà âëÿþùèé ñîáîé ïà ðñåð, ГЈГҐГåðèðóåìûé ñèñòåìîé gppg + public BlockNode root; // ÊîðГåâîé óçåë Г±ГЁГòà êñè÷åñêîãî äåðåâà + public Parser(AbstractScanner<ValueType, LexLocation> scanner) : base(scanner) { } + private bool InDefSect = false; +%} + +%output = SimpleYacc.cs + +%union { + public double dVal; + public int iVal; + public string sVal; + public Node nVal; + public ExprNode eVal; + public StatementNode stVal; + public BlockNode blVal; + } + +%using System.IO; +%using ProgramTree; + +%namespace SimpleParser + +%start progr + +%token BEGIN END CYCLE ASSIGN ASSIGNPLUS ASSIGNMINUS ASSIGNMULT SEMICOLON WRITE VAR PLUS MINUS MULT DIV LPAREN RPAREN COLUMN +%token <iVal> INUM +%token <dVal> RNUM +%token <sVal> ID + +%type <nVal> varlist +%type <eVal> expr ident T F +%type <stVal> statement assign block cycle write empty var +%type <blVal> stlist block + +%% +// Error: NonTerminal symbol "st" has no productions +// Warning: Terminating st fixes the following size-2 NonTerminal set + // {cycle, st} +// Error: There are 2 non-terminating NonTerminal Symbols + // {cycle, st} +// ------------------------------------------------------------------ + +progr : block { root = $1; } + ; + +stlist : statement + { + $$ = new BlockNode($1); + } + | stlist SEMICOLON statement + { + $1.Add($3); + $$ = $1; + } + ; + +statement: assign { $$ = $1; } + | block { $$ = $1; } + | cycle { $$ = $1; } + | write { $$ = $1; } + | var { $$ = $1; } + | empty { $$ = $1; } + ; + +empty : { $$ = new EmptyNode(); } + ; + +ident : ID + { + if (!InDefSect) + if (!SymbolTable.vars.ContainsKey($1)) + throw new Exception("("+@1.StartLine+","+@1.StartColumn+"): ÏåðåìåГГГ Гї "+$1+" ГГҐ îïèñà ГГ "); + $$ = new IdNode($1); + } + ; + +assign : ident ASSIGN expr { $$ = new AssignNode($1 as IdNode, $3); } + ; + +expr : expr PLUS T { $$ = new BinOpNode($1,$3,'+'); } + | expr MINUS T { $$ = new BinOpNode($1,$3,'-'); } + | T { $$ = $1; } + ; + +T : T MULT F { $$ = new BinOpNode($1,$3,'*'); } + | T DIV F { $$ = new BinOpNode($1,$3,'/'); } + | F { $$ = $1; } + ; + +F : ident { $$ = $1 as IdNode; } + | INUM { $$ = new IntNumNode($1); } + | LPAREN expr RPAREN { $$ = $2; } + ; + +block : BEGIN stlist END { $$ = $2; } + ; + +cycle : CYCLE expr st { $$ = new CycleNode($2,$3); } + ; + +write : WRITE LPAREN expr RPAREN { $$ = new WriteNode($3); } + ; + +var : VAR { InDefSect = true; } varlist + { + foreach (var v in ($3 as VarDefNode).vars) + SymbolTable.NewVarDef(v.Name, type.tint); + InDefSect = false; + } + ; + +varlist : ident + { + $$ = new VarDefNode($1 as IdNode); + } + | varlist COLUMN ident + { + ($1 as VarDefNode).Add($3 as IdNode); + $$ = $1; + } + ; + +%% + +// ========================================================================== + diff --git a/Module7/SimpleLanguage2/SimpleYacc.y b/Module7/SimpleLanguage2/SimpleYacc.y new file mode 100644 index 0000000..20087e0 --- /dev/null +++ b/Module7/SimpleLanguage2/SimpleYacc.y @@ -0,0 +1,119 @@ +%{ +// Эти объявления добавляются в класс GPPGParser, представляющий собой парсер, генерируемый системой gppg + public BlockNode root; // Корневой узел синтаксического дерева + public Parser(AbstractScanner<ValueType, LexLocation> scanner) : base(scanner) { } + private bool InDefSect = false; +%} + +%output = SimpleYacc.cs + +%union { + public double dVal; + public int iVal; + public string sVal; + public Node nVal; + public ExprNode eVal; + public StatementNode stVal; + public BlockNode blVal; + } + +%using System.IO; +%using ProgramTree; + +%namespace SimpleParser + +%start progr + +%token BEGIN END CYCLE ASSIGN ASSIGNPLUS ASSIGNMINUS ASSIGNMULT SEMICOLON WRITE VAR PLUS MINUS MULT DIV LPAREN RPAREN COLUMN +%token <iVal> INUM +%token <dVal> RNUM +%token <sVal> ID + +%type <eVal> expr ident T F +%type <stVal> statement assign block cycle write empty var varlist +%type <blVal> stlist block + +%% + +progr : block { root = $1; } + ; + +stlist : statement + { + $$ = new BlockNode($1); + } + | stlist SEMICOLON statement + { + $1.Add($3); + $$ = $1; + } + ; + +statement: assign { $$ = $1; } + | block { $$ = $1; } + | cycle { $$ = $1; } + | write { $$ = $1; } + | var { $$ = $1; } + | empty { $$ = $1; } + ; + +empty : { $$ = new EmptyNode(); } + ; + +ident : ID + { + if (!InDefSect) + if (!SymbolTable.vars.ContainsKey($1)) + throw new Exception("("+@1.StartLine+","+@1.StartColumn+"): Переменная "+$1+" не описана"); + $$ = new IdNode($1); + } + ; + +assign : ident ASSIGN expr { $$ = new AssignNode($1 as IdNode, $3); } + ; + +expr : expr PLUS T { $$ = new BinOpNode($1,$3,'+'); } + | expr MINUS T { $$ = new BinOpNode($1,$3,'-'); } + | T { $$ = $1; } + ; + +T : T MULT F { $$ = new BinOpNode($1,$3,'*'); } + | T DIV F { $$ = new BinOpNode($1,$3,'/'); } + | F { $$ = $1; } + ; + +F : ident { $$ = $1 as IdNode; } + | INUM { $$ = new IntNumNode($1); } + | LPAREN expr RPAREN { $$ = $2; } + ; + +block : BEGIN stlist END { $$ = $2; } + ; + +cycle : CYCLE expr statement { $$ = new CycleNode($2,$3); } + ; + +write : WRITE LPAREN expr RPAREN { $$ = new WriteNode($3); } + ; + +var : VAR { InDefSect = true; } varlist + { + foreach (var v in ($3 as VarDefNode).vars) + SymbolTable.NewVarDef(v.Name, type.tint); + InDefSect = false; + } + ; + +varlist : ident + { + $$ = new VarDefNode($1 as IdNode); + } + | varlist COLUMN ident + { + ($1 as VarDefNode).Add($3 as IdNode); + $$ = $1; + } + ; + +%% + diff --git a/Module7/SimpleLanguage2/Visitors/AssignCountVisitor.cs b/Module7/SimpleLanguage2/Visitors/AssignCountVisitor.cs new file mode 100644 index 0000000..43d8554 --- /dev/null +++ b/Module7/SimpleLanguage2/Visitors/AssignCountVisitor.cs @@ -0,0 +1,23 @@ +п»їusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProgramTree; + +namespace SimpleLang.Visitors +{ + class AssignCountVisitor : AutoVisitor + { + public int Count = 0; + public override void VisitAssignNode(AssignNode a) + { + Count += 1; + } + public override void VisitWriteNode(WriteNode w) + { + } + public override void VisitVarDefNode(VarDefNode w) + { + } + } +} diff --git a/Module7/SimpleLanguage2/Visitors/AutoVisitor.cs b/Module7/SimpleLanguage2/Visitors/AutoVisitor.cs new file mode 100644 index 0000000..7c92bab --- /dev/null +++ b/Module7/SimpleLanguage2/Visitors/AutoVisitor.cs @@ -0,0 +1,45 @@ +п»їusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProgramTree; + +namespace SimpleLang.Visitors +{ + // базовая логика РѕР±С…РѕРґР° без действий + // Если нужны действия или другая логика РѕР±С…РѕРґР°, то соответствующие методы надо переопределять + // РџСЂРё переопределении методов для задания действий необходимо РЅРµ забывать обходить подузлы + class AutoVisitor: Visitor + { + public override void VisitBinOpNode(BinOpNode binop) + { + binop.Left.Visit(this); + binop.Right.Visit(this); + } + public override void VisitAssignNode(AssignNode a) + { + // для каких-то визиторов РїРѕСЂСЏРґРѕРє может быть обратный - вначале обойти выражение, потом - идентификатор + a.Id.Visit(this); + a.Expr.Visit(this); + } + public override void VisitCycleNode(CycleNode c) + { + c.Expr.Visit(this); + c.Stat.Visit(this); + } + public override void VisitBlockNode(BlockNode bl) + { + foreach (var st in bl.StList) + st.Visit(this); + } + public override void VisitWriteNode(WriteNode w) + { + w.Expr.Visit(this); + } + public override void VisitVarDefNode(VarDefNode w) + { + foreach (var v in w.vars) + v.Visit(this); + } + } +} diff --git a/Module7/SimpleLanguage2/Visitors/PrettyPrintVisitor.cs b/Module7/SimpleLanguage2/Visitors/PrettyPrintVisitor.cs new file mode 100644 index 0000000..87892b1 --- /dev/null +++ b/Module7/SimpleLanguage2/Visitors/PrettyPrintVisitor.cs @@ -0,0 +1,88 @@ +п»їusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProgramTree; + +namespace SimpleLang.Visitors +{ + class PrettyPrintVisitor: Visitor + { + public string Text = ""; + private int Indent = 0; + + private string IndentStr() + { + return new string(' ', Indent); + } + private void IndentPlus() + { + Indent += 2; + } + private void IndentMinus() + { + Indent -= 2; + } + public override void VisitIdNode(IdNode id) + { + Text += id.Name; + } + public override void VisitIntNumNode(IntNumNode num) + { + Text += num.Num.ToString(); + } + public override void VisitBinOpNode(BinOpNode binop) + { + Text += "("; + binop.Left.Visit(this); + Text += " " + binop.Op + " "; + binop.Right.Visit(this); + Text += ")"; + } + public override void VisitAssignNode(AssignNode a) + { + Text += IndentStr(); + a.Id.Visit(this); + Text += " := "; + a.Expr.Visit(this); + } + public override void VisitCycleNode(CycleNode c) + { + Text += IndentStr() + "cycle "; + c.Expr.Visit(this); + Text += Environment.NewLine; + c.Stat.Visit(this); + } + public override void VisitBlockNode(BlockNode bl) + { + Text += IndentStr() + "begin" + Environment.NewLine; + IndentPlus(); + + var Count = bl.StList.Count; + + if (Count>0) + bl.StList[0].Visit(this); + for (var i = 1; i < Count; i++) + { + Text += ';'; + if (!(bl.StList[i] is EmptyNode)) + Text += Environment.NewLine; + bl.StList[i].Visit(this); + } + IndentMinus(); + Text += Environment.NewLine + IndentStr() + "end"; + } + public override void VisitWriteNode(WriteNode w) + { + Text += IndentStr() + "write("; + w.Expr.Visit(this); + Text += ")"; + } + public override void VisitVarDefNode(VarDefNode w) + { + Text += IndentStr() + "var " + w.vars[0].Name; + for (int i = 1; i < w.vars.Count; i++) + Text += ',' + w.vars[i].Name; + } + } +} diff --git a/Module7/SimpleLanguage2/Visitors/Visitor.cs b/Module7/SimpleLanguage2/Visitors/Visitor.cs new file mode 100644 index 0000000..b9dcae0 --- /dev/null +++ b/Module7/SimpleLanguage2/Visitors/Visitor.cs @@ -0,0 +1,21 @@ +п»їusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProgramTree; + +namespace SimpleLang.Visitors +{ + public abstract class Visitor + { + public virtual void VisitIdNode(IdNode id) { } + public virtual void VisitIntNumNode(IntNumNode num) { } + public virtual void VisitBinOpNode(BinOpNode binop) { } + public virtual void VisitAssignNode(AssignNode a) { } + public virtual void VisitCycleNode(CycleNode c) { } + public virtual void VisitBlockNode(BlockNode bl) { } + public virtual void VisitWriteNode(WriteNode w) { } + public virtual void VisitVarDefNode(VarDefNode w) { } + public virtual void VisitEmptyNode(EmptyNode w) { } + } +} diff --git a/Module7/SimpleLanguage2/a.txt b/Module7/SimpleLanguage2/a.txt new file mode 100644 index 0000000..14eeab4 --- /dev/null +++ b/Module7/SimpleLanguage2/a.txt @@ -0,0 +1,11 @@ +begin + var a,b,d; + b := 2; + a := 3; + a := a * 4 + b;;; + cycle 3 + begin + a := a + 1; + write(a) + end +end diff --git a/Module7/SimpleLanguage2/generateParserScanner.bat b/Module7/SimpleLanguage2/generateParserScanner.bat new file mode 100644 index 0000000..7ca5476 --- /dev/null +++ b/Module7/SimpleLanguage2/generateParserScanner.bat @@ -0,0 +1,3 @@ +cls +gplex.exe /unicode SimpleLex.lex +gppg.exe /no-lines /gplex SimpleYacc.y diff --git a/Module8/SimpleLanguage3/Main.cs b/Module8/SimpleLanguage3/Main.cs new file mode 100644 index 0000000..4c8a1f5 --- /dev/null +++ b/Module8/SimpleLanguage3/Main.cs @@ -0,0 +1,65 @@ +п»їusing System; +using System.IO; +using System.Text; +using System.Reflection; +using System.Collections.Generic; +using SimpleScanner; +using SimpleParser; +using SimpleLang.Visitors; + +namespace SimpleCompiler +{ + public class SimpleCompilerMain + { + public static void Main() + { + string FileName = @"..\..\a.txt"; + try + { + string Text = File.ReadAllText(FileName); + + Scanner scanner = new Scanner(); + scanner.SetSource(Text, 0); + + Parser parser = new Parser(scanner); + + var b = parser.Parse(); + if (!b) + Console.WriteLine("Ошибка"); + else + { + Console.WriteLine("Синтаксическое дерево построено"); + + var avis = new AssignCountVisitor(); + parser.root.Visit(avis); + Console.WriteLine("Количество присваиваний = {0}", avis.Count); + Console.WriteLine("-------------------------------"); + + var pp = new PrettyPrintVisitor(); + parser.root.Visit(pp); + Console.WriteLine(pp.Text); + Console.WriteLine("-------------------------------"); + + var code = new GenCodeVisitor(); + parser.root.Visit(code); + code.EndProgram(); + //code.PrintCommands(); + Console.WriteLine("-------------------------------"); + + code.RunProgram(); + } + } + catch (FileNotFoundException) + { + Console.WriteLine("Файл {0} РЅРµ найден", FileName); + } + catch (Exception e) + { + Console.WriteLine("{0}", e); + } + + Console.ReadLine(); + } + + } +} diff --git a/Module8/SimpleLanguage3/ParserHelper.cs b/Module8/SimpleLanguage3/ParserHelper.cs new file mode 100644 index 0000000..a085ecd --- /dev/null +++ b/Module8/SimpleLanguage3/ParserHelper.cs @@ -0,0 +1,33 @@ +п»їusing System.Collections.Generic; +using System; + +namespace SimpleParser +{ + + public enum type { tint, tdouble }; + + public static class SymbolTable // Таблица символов + { + public static Dictionary<string, type> vars = new Dictionary<string, type>(); // таблица символов + public static void NewVarDef(string name, type t) + { + if (vars.ContainsKey(name)) + throw new Exception("Переменная " + name + " уже определена"); + else vars.Add(name, t); + } + } + + public class LexException : Exception + { + public LexException(string msg) : base(msg) { } + } + + public class SyntaxException : Exception + { + public SyntaxException(string msg) : base(msg) { } + } + + public static class ParserHelper + { + } +} \ No newline at end of file diff --git a/Module8/SimpleLanguage3/ProgramTree.cs b/Module8/SimpleLanguage3/ProgramTree.cs new file mode 100644 index 0000000..e48dcb5 --- /dev/null +++ b/Module8/SimpleLanguage3/ProgramTree.cs @@ -0,0 +1,145 @@ +п»їusing System.Collections.Generic; +using SimpleLang.Visitors; + +namespace ProgramTree +{ + public enum AssignType { Assign, AssignPlus, AssignMinus, AssignMult, AssignDivide }; + + public abstract class Node // базовый класс для всех узлов + { + public abstract void Visit(Visitor v); + } + + public abstract class ExprNode : Node // базовый класс для всех выражений + { + } + + public class IdNode : ExprNode + { + public string Name { get; set; } + public IdNode(string name) { Name = name; } + public override void Visit(Visitor v) + { + v.VisitIdNode(this); + } + } + + public class IntNumNode : ExprNode + { + public int Num { get; set; } + public IntNumNode(int num) { Num = num; } + public override void Visit(Visitor v) + { + v.VisitIntNumNode(this); + } + } + + public class BinOpNode : ExprNode + { + public ExprNode Left { get; set; } + public ExprNode Right { get; set; } + public char Op { get; set; } + public BinOpNode(ExprNode Left, ExprNode Right, char op) + { + this.Left = Left; + this.Right = Right; + this.Op = op; + } + public override void Visit(Visitor v) + { + v.VisitBinOpNode(this); + } + } + + public abstract class StatementNode : Node // базовый класс для всех операторов + { + } + + public class AssignNode : StatementNode + { + public IdNode Id { get; set; } + public ExprNode Expr { get; set; } + public AssignType AssOp { get; set; } + public AssignNode(IdNode id, ExprNode expr, AssignType assop = AssignType.Assign) + { + Id = id; + Expr = expr; + AssOp = assop; + } + public override void Visit(Visitor v) + { + v.VisitAssignNode(this); + } + } + + public class CycleNode : StatementNode + { + public ExprNode Expr { get; set; } + public StatementNode Stat { get; set; } + public CycleNode(ExprNode expr, StatementNode stat) + { + Expr = expr; + Stat = stat; + } + public override void Visit(Visitor v) + { + v.VisitCycleNode(this); + } + } + + public class BlockNode : StatementNode + { + public List<StatementNode> StList = new List<StatementNode>(); + public BlockNode(StatementNode stat) + { + Add(stat); + } + public void Add(StatementNode stat) + { + StList.Add(stat); + } + public override void Visit(Visitor v) + { + v.VisitBlockNode(this); + } + } + + public class WriteNode : StatementNode + { + public ExprNode Expr { get; set; } + public WriteNode(ExprNode Expr) + { + this.Expr = Expr; + } + public override void Visit(Visitor v) + { + v.VisitWriteNode(this); + } + } + + public class EmptyNode : StatementNode + { + public override void Visit(Visitor v) + { + v.VisitEmptyNode(this); + } + } + + public class VarDefNode : StatementNode + { + public List<IdNode> vars = new List<IdNode>(); + public VarDefNode(IdNode id) + { + Add(id); + } + + public void Add(IdNode id) + { + vars.Add(id); + } + public override void Visit(Visitor v) + { + v.VisitVarDefNode(this); + } + } +} \ No newline at end of file diff --git a/Module8/SimpleLanguage3/Properties/AssemblyInfo.cs b/Module8/SimpleLanguage3/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..896cc99 --- /dev/null +++ b/Module8/SimpleLanguage3/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +п»їusing System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Управление общими сведениями Рѕ СЃР±РѕСЂРєРµ осуществляется СЃ помощью +// набора атрибутов. Рзмените значения этих атрибутов, чтобы изменить сведения, +// связанные СЃРѕ СЃР±РѕСЂРєРѕР№. +[assembly: AssemblyTitle("SimpleLang")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SimpleLang")] +[assembly: AssemblyCopyright("Copyright В© 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Параметр ComVisible СЃРѕ значением FALSE делает типы РІ СЃР±РѕСЂРєРµ невидимыми +// для COM-компонентов. Если требуется обратиться Рє типу РІ этой СЃР±РѕСЂРєРµ через +// COM, задайте атрибуту ComVisible значение TRUE для этого типа. +[assembly: ComVisible(false)] + +// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM +[assembly: Guid("06dba63f-4805-4cd3-8a93-b329b2c7e37b")] + +// Сведения Рѕ версии СЃР±РѕСЂРєРё состоят РёР· следующих четырех значений: +// +// РћСЃРЅРѕРІРЅРѕР№ номер версии +// Дополнительный номер версии +// Номер построения +// Редакция +// +// Можно задать РІСЃРµ значения или принять номер построения Рё номер редакции РїРѕ умолчанию, +// используя "*", как показано ниже: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Module8/SimpleLanguage3/ShiftReduceParserCode.cs b/Module8/SimpleLanguage3/ShiftReduceParserCode.cs new file mode 100644 index 0000000..c110ba1 --- /dev/null +++ b/Module8/SimpleLanguage3/ShiftReduceParserCode.cs @@ -0,0 +1,944 @@ +// Gardens Point Parser Generator +// Copyright (c) Wayne Kelly, QUT 2005-2009 +// (see accompanying GPPGcopyright.rtf) +#define EXPORT_GPPG + +using System; +using System.Text; +using System.Globalization; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; + +namespace QUT.Gppg +{ + /// <summary> + /// Abstract class for GPPG shift-reduce parsers. + /// Parsers generated by GPPG derive from this base + /// class, overriding the abstract Initialize() and + /// DoAction() methods. + /// </summary> + /// <typeparam name="TValue">Semantic value type</typeparam> + /// <typeparam name="TSpan">Location type</typeparam> +#if EXPORT_GPPG + public abstract class ShiftReduceParser<TValue, TSpan> +#else + internal abstract class ShiftReduceParser<TValue, TSpan> +#endif + where TSpan : IMerge<TSpan>, new() + { + public AbstractScanner<TValue, TSpan> scanner; + /// <summary> + /// The abstract scanner for this parser. + /// </summary> + protected AbstractScanner<TValue, TSpan> Scanner { + get { return scanner; } + set { scanner = value; } + } + + /// <summary> + /// Constructor for base class + /// </summary> + /// <param name="scanner">Scanner instance for this parser</param> + protected ShiftReduceParser(AbstractScanner<TValue, TSpan> scanner) + { + this.scanner = scanner; + } + + // ============================================================== + // TECHNICAL EXPLANATION. + // Why the next two fields are not exposed via properties. + // ============================================================== + // These fields are of the generic parameter types, and are + // frequently instantiated as struct types in derived classes. + // Semantic actions are defined in the derived classes and refer + // to instance fields of these structs. Is such cases the code + // "get_CurrentSemanticValue().myField = blah;" will fail since + // the getter pushes the value of the field, not the reference. + // So, in the presence of properties, gppg would need to encode + // such field accesses as ... + // "tmp = get_CurrentSemanticValue(); // Fetch value + // tmp.myField = blah; // update + // set_CurrentSemanticValue(tmp); " // Write update back. + // There is no issue if TValue is restricted to be a ref type. + // The same explanation applies to scanner.yylval. + // ============================================================== + /// <summary> + /// The current value of the "$$" symbolic variable in the parser + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + protected TValue CurrentSemanticValue; + + /// <summary> + /// The current value of the "@$" symbolic variable in the parser + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + protected TSpan CurrentLocationSpan; + + private TSpan LastSpan; + private int NextToken; + private State FsaState; + private bool recovering; + private int tokensSinceLastError; + + private PushdownPrefixState<State> StateStack = new PushdownPrefixState<State>(); + private PushdownPrefixState<TValue> valueStack = new PushdownPrefixState<TValue>(); + private PushdownPrefixState<TSpan> locationStack = new PushdownPrefixState<TSpan>(); + + /// <summary> + /// The stack of semantic value (YYSTYPE) values. + /// </summary> + protected PushdownPrefixState<TValue> ValueStack { get { return valueStack; } } + + /// <summary> + /// The stack of location value (YYLTYPE) varlues. + /// </summary> + protected PushdownPrefixState<TSpan> LocationStack { get { return locationStack; } } + + private int errorToken; + private int endOfFileToken; + private string[] nonTerminals; + private State[] states; + private Rule[] rules; + + /// <summary> + /// Initialization method to allow derived classes + /// to insert the rule list into this base class. + /// </summary> + /// <param name="rules">The array of Rule objects</param> + protected void InitRules(Rule[] rules) { this.rules = rules; } + + /// <summary> + /// Initialization method to allow derived classes to + /// insert the states table into this base class. + /// </summary> + /// <param name="states">The pre-initialized states table</param> + protected void InitStates(State[] states) { this.states = states; } + + /// <summary> + /// OBSOLETE FOR VERSION 1.4.0 + /// </summary> + /// <param name="size"></param> + protected void InitStateTable(int size) { states = new State[size]; } + + /// <summary> + /// Initialization method to allow derived classes + /// to insert the special value for the error and EOF tokens. + /// </summary> + /// <param name="err">The error state ordinal</param> + /// <param name="end">The EOF stat ordinal</param> + protected void InitSpecialTokens(int err, int end) + { + errorToken = err; + endOfFileToken = end; + } + + /// <summary> + /// Initialization method to allow derived classes to + /// insert the non-terminal symbol names into this base class. + /// </summary> + /// <param name="names">Non-terminal symbol names</param> + protected void InitNonTerminals(string[] names) { nonTerminals = names; } + + #region YYAbort, YYAccept etcetera. + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class AcceptException : Exception + { + internal AcceptException() { } + protected AcceptException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class AbortException : Exception + { + internal AbortException() { } + protected AbortException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + // Reason for FxCop message suppression - + // This exception cannot escape from the local context + private class ErrorException : Exception + { + internal ErrorException() { } + protected ErrorException(SerializationInfo i, StreamingContext c) : base(i, c) { } + } + + // The following methods are only called from within + // a semantic action. The thrown exceptions can never + // propagate outside the ShiftReduceParser class in + // which they are nested. + + /// <summary> + /// Force parser to terminate, returning "true" + /// </summary> + protected static void YYAccept() { throw new AcceptException(); } + + /// <summary> + /// Force parser to terminate, returning "false" + /// </summary> + protected static void YYAbort() { throw new AbortException(); } + + /// <summary> + /// Force parser to terminate, returning + /// "false" if error recovery fails. + /// </summary> + protected static void YYError() { throw new ErrorException(); } + + /// <summary> + /// Check if parser in error recovery state. + /// </summary> + protected bool YYRecovering { get { return recovering; } } + #endregion + + /// <summary> + /// Abstract base method. ShiftReduceParser calls this + /// to initialize the base class data structures. Concrete + /// parser classes must override this method. + /// </summary> + protected abstract void Initialize(); + + /// <summary> + /// Main entry point of the Shift-Reduce Parser. + /// </summary> + /// <returns>True if parse succeeds, else false for + /// unrecoverable errors</returns> + public bool Parse() + { + Initialize(); // allow derived classes to instantiate rules, states and nonTerminals + + NextToken = 0; + FsaState = states[0]; + + StateStack.Push(FsaState); + valueStack.Push(CurrentSemanticValue); + LocationStack.Push(CurrentLocationSpan); + + while (true) + { +#if TRACE_ACTIONS + Console.Error.WriteLine("Entering state {0} ", FsaState.number); +#endif + int action = FsaState.defaultAction; + + if (FsaState.ParserTable != null) + { + if (NextToken == 0) + { +#if TRACE_ACTIONS + Console.Error.Write("Reading a token: "); +#endif + // We save the last token span, so that the location span + // of production right hand sides that begin or end with a + // nullable production will be correct. + LastSpan = scanner.yylloc; + NextToken = scanner.yylex(); + } + +#if TRACE_ACTIONS + Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken)); +#endif + if (FsaState.ParserTable.ContainsKey(NextToken)) + action = FsaState.ParserTable[NextToken]; + } + + if (action > 0) // shift + { + Shift(action); + } + else if (action < 0) // reduce + { + try + { + Reduce(-action); + if (action == -1) // accept + return true; + } + catch (Exception x) + { + if (x is AbortException) + return false; + else if (x is AcceptException) + return true; + else if (x is ErrorException && !ErrorRecovery()) + return false; + else + throw; // Rethrow x, preserving information. + + } + } + else if (action == 0) // error + if (!ErrorRecovery()) + return false; + } + } + + private void Shift(int stateIndex) + { +#if TRACE_ACTIONS + Console.Error.Write("Shifting token {0}, ", TerminalToString(NextToken)); +#endif + FsaState = states[stateIndex]; + + valueStack.Push(scanner.yylval); + StateStack.Push(FsaState); + LocationStack.Push(scanner.yylloc); + + if (recovering) + { + if (NextToken != errorToken) + tokensSinceLastError++; + + if (tokensSinceLastError > 5) + recovering = false; + } + + if (NextToken != endOfFileToken) + NextToken = 0; + } + + private void Reduce(int ruleNumber) + { +#if TRACE_ACTIONS + DisplayRule(ruleNumber); +#endif + Rule rule = rules[ruleNumber]; + // + // Default actions for unit productions. + // + if (rule.RightHandSide.Length == 1) + { + CurrentSemanticValue = valueStack.TopElement(); // Default action: $$ = $1; + CurrentLocationSpan = LocationStack.TopElement(); // Default action "@$ = @1; + } + else + { + if (rule.RightHandSide.Length == 0) + { + // Create a new blank value. + // Explicit semantic action may mutate this value + CurrentSemanticValue = default(TValue); + // The location span for an empty production will start with the + // beginning of the next lexeme, and end with the finish of the + // previous lexeme. This gives the correct behaviour when this + // nonsense value is used in later Merge operations. + CurrentLocationSpan = (scanner.yylloc != null && LastSpan != null ? + scanner.yylloc.Merge(LastSpan) : + default(TSpan)); + } + else + { + // Default action: $$ = $1; + CurrentSemanticValue = valueStack.TopElement(); + // Default action "@$ = @1.Merge(@N)" for location info. + TSpan at1 = LocationStack[LocationStack.Depth - rule.RightHandSide.Length]; + TSpan atN = LocationStack[LocationStack.Depth - 1]; + CurrentLocationSpan = + ((at1 != null && atN != null) ? at1.Merge(atN) : default(TSpan)); + } + } + + DoAction(ruleNumber); + + for (int i = 0; i < rule.RightHandSide.Length; i++) + { + StateStack.Pop(); + valueStack.Pop(); + LocationStack.Pop(); + } + +#if TRACE_ACTIONS + DisplayStack(); +#endif + FsaState = StateStack.TopElement(); + + if (FsaState.Goto.ContainsKey(rule.LeftHandSide)) + FsaState = states[FsaState.Goto[rule.LeftHandSide]]; + + StateStack.Push(FsaState); + valueStack.Push(CurrentSemanticValue); + LocationStack.Push(CurrentLocationSpan); + } + + /// <summary> + /// Execute the selected action from array. + /// Must be overriden in derived classes. + /// </summary> + /// <param name="actionNumber">Index of the action to perform</param> + protected abstract void DoAction(int actionNumber); + + private bool ErrorRecovery() + { + bool discard; + + if (!recovering) // if not recovering from previous error + ReportError(); + + if (!FindErrorRecoveryState()) + return false; + // + // The interim fix for the "looping in error recovery" + // artifact involved moving the setting of the recovering + // bool until after invalid tokens have been discarded. + // + ShiftErrorToken(); + discard = DiscardInvalidTokens(); + recovering = true; + tokensSinceLastError = 0; + return discard; + } + + private void ReportError1() + { + StringBuilder errorMsg = new StringBuilder(); + errorMsg.AppendFormat("Syntax error, unexpected {0}", TerminalToString(NextToken)); + + if (FsaState.ParserTable.Count < 7) + { + bool first = true; + foreach (int terminal in FsaState.ParserTable.Keys) + { + if (first) + errorMsg.Append(", expecting "); + else + errorMsg.Append(", or "); + + errorMsg.Append(TerminalToString(terminal)); + first = false; + } + } + scanner.yyerror(errorMsg.ToString()); + } + + private void ReportError() + { + object[] args = new object[FsaState.ParserTable.Keys.Count+1]; + args[0] = TerminalToString(NextToken); + int i=1; + foreach (int terminal in FsaState.ParserTable.Keys) + { + args[i] = TerminalToString(terminal); + i++; + } + scanner.yyerror("",args); + } + + private void ShiftErrorToken() + { + int old_next = NextToken; + NextToken = errorToken; + + Shift(FsaState.ParserTable[NextToken]); + +#if TRACE_ACTIONS + Console.Error.WriteLine("Entering state {0} ", FsaState.number); +#endif + NextToken = old_next; + } + + private bool FindErrorRecoveryState() + { + while (true) // pop states until one found that accepts error token + { + if (FsaState.ParserTable != null && + FsaState.ParserTable.ContainsKey(errorToken) && + FsaState.ParserTable[errorToken] > 0) // shift + return true; + +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: popping state {0}", StateStack.Top().number); +#endif + StateStack.Pop(); + valueStack.Pop(); + LocationStack.Pop(); + +#if TRACE_ACTIONS + DisplayStack(); +#endif + if (StateStack.IsEmpty()) + { +#if TRACE_ACTIONS + Console.Error.Write("Aborting: didn't find a state that accepts error token"); +#endif + return false; + } + else + FsaState = StateStack.TopElement(); + } + } + + private bool DiscardInvalidTokens() + { + + int action = FsaState.defaultAction; + + if (FsaState.ParserTable != null) + { + // Discard tokens until find one that works ... + while (true) + { + if (NextToken == 0) + { +#if TRACE_ACTIONS + Console.Error.Write("Reading a token: "); +#endif + NextToken = scanner.yylex(); + } + +#if TRACE_ACTIONS + Console.Error.WriteLine("Next token is {0}", TerminalToString(NextToken)); +#endif + if (NextToken == endOfFileToken) + return false; + + if (FsaState.ParserTable.ContainsKey(NextToken)) + action = FsaState.ParserTable[NextToken]; + + if (action != 0) + return true; + else + { +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: Discarding {0}", TerminalToString(NextToken)); +#endif + NextToken = 0; + } + } + } + else if (recovering && tokensSinceLastError == 0) + { + // + // Boolean recovering is not set until after the first + // error token has been shifted. Thus if we get back + // here with recovering set and no tokens read we are + // looping on the same error recovery action. This + // happens if current_state.ParserTable is null because + // the state has an LR(0) reduction, but not all + // lookahead tokens are valid. This only occurs for + // error productions that *end* on "error". + // + // This action discards tokens one at a time until + // the looping stops. Another attack would be to always + // use the LALR(1) table if a production ends on "error" + // +#if TRACE_ACTIONS + Console.Error.WriteLine("Error: panic discard of {0}", TerminalToString(NextToken)); +#endif + if (NextToken == endOfFileToken) + return false; + NextToken = 0; + return true; + } + else + return true; + + } + + /// <summary> + /// Traditional YACC method. Discards the next input token. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyclearin")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyclearin")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + protected void yyclearin() { NextToken = 0; } + + /// <summary> + /// Tradional YACC method. Clear the "recovering" flag. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerrok")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerrok")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + protected void yyerrok() + { + recovering = false; + } + + /// <summary> + /// OBSOLETE FOR VERSION 1.4.0 + /// Method used by derived types to insert new + /// state instances in the "states" array. + /// </summary> + /// <param name="stateNumber">index of the state</param> + /// <param name="state">data for the state</param> + protected void AddState(int stateNumber, State state) + { + states[stateNumber] = state; + state.number = stateNumber; + } + + private void DisplayStack() + { + Console.Error.Write("State now"); + for (int i = 0; i < StateStack.Depth; i++) + Console.Error.Write(" {0}", StateStack[i].number); + Console.Error.WriteLine(); + } + + private void DisplayRule(int ruleNumber) + { + Console.Error.Write("Reducing stack by rule {0}, ", ruleNumber); + DisplayProduction(rules[ruleNumber]); + } + + private void DisplayProduction(Rule rule) + { + if (rule.RightHandSide.Length == 0) + Console.Error.Write("/* empty */ "); + else + foreach (int symbol in rule.RightHandSide) + Console.Error.Write("{0} ", SymbolToString(symbol)); + + Console.Error.WriteLine("-> {0}", SymbolToString(rule.LeftHandSide)); + } + + /// <summary> + /// Abstract state class naming terminal symbols. + /// This is overridden by derived classes with the + /// name (or alias) to be used in error messages. + /// </summary> + /// <param name="terminal">The terminal ordinal</param> + /// <returns></returns> + protected abstract string TerminalToString(int terminal); + + private string SymbolToString(int symbol) + { + if (symbol < 0) + return nonTerminals[-symbol]; + else + return TerminalToString(symbol); + } + + /// <summary> + /// Return text representation of argument character + /// </summary> + /// <param name="input">The character to convert</param> + /// <returns>String representation of the character</returns> + protected static string CharToString(char input) + { + switch (input) + { + case '\a': return @"'\a'"; + case '\b': return @"'\b'"; + case '\f': return @"'\f'"; + case '\n': return @"'\n'"; + case '\r': return @"'\r'"; + case '\t': return @"'\t'"; + case '\v': return @"'\v'"; + case '\0': return @"'\0'"; + default: return string.Format(CultureInfo.InvariantCulture, "'{0}'", input); + } + } + } + + /// <summary> + /// Classes implementing this interface must supply a + /// method that merges two location objects to return + /// a new object of the same type. + /// GPPG-generated parsers have the default location + /// action equivalent to "@$ = @1.Merge(@N);" where N + /// is the right-hand-side length of the production. + /// </summary> + /// <typeparam name="TSpan">The Location type</typeparam> +#if EXPORT_GPPG + public interface IMerge<TSpan> +#else + internal interface IMerge<TSpan> +#endif + { + /// <summary> + /// Interface method that creates a location object from + /// the current and last object. Typically used to create + /// a location object extending from the start of the @1 + /// object to the end of the @N object. + /// </summary> + /// <param name="last">The lexically last object to merge</param> + /// <returns>The merged location object</returns> + TSpan Merge(TSpan last); + } + + /// <summary> + /// This is the default class that carries location + /// information from the scanner to the parser. + /// If you don't declare "%YYLTYPE Foo" the parser + /// will expect to deal with this type. + /// </summary> +#if EXPORT_GPPG + public class LexLocation : IMerge<LexLocation> +#else + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + internal class LexLocation : IMerge<LexLocation> +#endif + { + private int startLine; // start line + private int startColumn; // start column + private int endLine; // end line + private int endColumn; // end column + + /// <summary> + /// The line at which the text span starts. + /// </summary> + public int StartLine { get { return startLine; } } + + /// <summary> + /// The column at which the text span starts. + /// </summary> + public int StartColumn { get { return startColumn; } } + + /// <summary> + /// The line on which the text span ends. + /// </summary> + public int EndLine { get { return endLine; } } + + /// <summary> + /// The column of the first character + /// beyond the end of the text span. + /// </summary> + public int EndColumn { get { return endColumn; } } + + /// <summary> + /// Default no-arg constructor. + /// </summary> + public LexLocation() + { } + + /// <summary> + /// Constructor for text-span with given start and end. + /// </summary> + /// <param name="sl">start line</param> + /// <param name="sc">start column</param> + /// <param name="el">end line </param> + /// <param name="ec">end column</param> + public LexLocation(int sl, int sc, int el, int ec) + { startLine = sl; startColumn = sc; endLine = el; endColumn = ec; } + + /// <summary> + /// Create a text location which spans from the + /// start of "this" to the end of the argument "last" + /// </summary> + /// <param name="last">The last location in the result span</param> + /// <returns>The merged span</returns> + public LexLocation Merge(LexLocation last) + { return new LexLocation(this.startLine, this.startColumn, last.endLine, last.endColumn); } + + } + + /// <summary> + /// Abstract scanner class that GPPG expects its scanners to + /// extend. + /// </summary> + /// <typeparam name="TValue">Semantic value type YYSTYPE</typeparam> + /// <typeparam name="TSpan">Source location type YYLTYPE</typeparam> +#if EXPORT_GPPG + public abstract class AbstractScanner<TValue, TSpan> +#else + internal abstract class AbstractScanner<TValue, TSpan> +#endif + where TSpan : IMerge<TSpan> + { + /// <summary> + /// Lexical value optionally set by the scanner. The value + /// is of the %YYSTYPE type declared in the parser spec. + /// </summary> + [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylval")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylval")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + // A field must be declared for this value of parametric type, + // since it may be instantiated by a value struct. If it were + // implemented as a property, machine generated code in derived + // types would not be able to select on the returned value. + public TValue yylval; // Lexical value: set by scanner + + /// <summary> + /// Current scanner location property. The value is of the + /// type declared by %YYLTYPE in the parser specification. + /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylloc")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylloc")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public virtual TSpan yylloc + { + get { return default(TSpan); } // Empty implementation allowing + set { /* skip */ } // yylloc to be ignored entirely. + } + + /// <summary> + /// Main call point for LEX-like scanners. Returns an int + /// corresponding to the token recognized by the scanner. + /// </summary> + /// <returns>An int corresponding to the token</returns> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public abstract int yylex(); + + /// <summary> + /// Traditional error reporting provided by LEX-like scanners + /// to their YACC-like clients. + /// </summary> + /// <param name="format">Message format string</param> + /// <param name="args">Optional array of args</param> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyerror")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyerror")] + // Reason for FxCop message suppression - + // This is a traditional name for YACC-like functionality + public virtual void yyerror(string format, params object[] args) { } + } + + /// <summary> + /// Encapsulated state for the parser. + /// Opaque to users, visible to the tool-generated code. + /// </summary> +#if EXPORT_GPPG + public class State +#else + internal class State +#endif + { + internal int number; + internal Dictionary<int, int> ParserTable; // Terminal -> ParseAction + internal Dictionary<int, int> Goto; // NonTerminal -> State; + internal int defaultAction; // = 0; // ParseAction + + /// <summary> + /// State transition data for this state. Pairs of elements of the + /// goto array associate symbol ordinals with next state indices. + /// The actions array is passed to another constructor. + /// </summary> + /// <param name="actions">The action list</param> + /// <param name="goToList">Next state data</param> + public State(int[] actions, int[] goToList) + : this(actions) + { + Goto = new Dictionary<int, int>(); + for (int i = 0; i < goToList.Length; i += 2) + Goto.Add(goToList[i], goToList[i + 1]); + } + + /// <summary> + /// Action data for this state. Pairs of elements of the + /// action array associate action ordinals with each of + /// those symbols that have actions in the current state. + /// </summary> + /// <param name="actions">The action array</param> + public State(int[] actions) + { + ParserTable = new Dictionary<int, int>(); + for (int i = 0; i < actions.Length; i += 2) + ParserTable.Add(actions[i], actions[i + 1]); + } + + /// <summary> + /// Set the default action for this state. + /// </summary> + /// <param name="defaultAction">Ordinal of the default action</param> + public State(int defaultAction) + { + this.defaultAction = defaultAction; + } + + /// <summary> + /// Set the default action and the state transition table. + /// </summary> + /// <param name="defaultAction">The default action</param> + /// <param name="goToList">Transitions from this state</param> + public State(int defaultAction, int[] goToList) + : this(defaultAction) + { + Goto = new Dictionary<int, int>(); + for (int i = 0; i < goToList.Length; i += 2) + Goto.Add(goToList[i], goToList[i + 1]); + } + } + + /// <summary> + /// Rule representation at runtime. + /// </summary> +#if EXPORT_GPPG + public class Rule +#else + internal class Rule +#endif + { + internal int LeftHandSide; // symbol + internal int[] RightHandSide; // symbols + + /// <summary> + /// Rule constructor. This holds the ordinal of + /// the left hand side symbol, and the list of + /// right hand side symbols, in lexical order. + /// </summary> + /// <param name="left">The LHS non-terminal</param> + /// <param name="right">The RHS symbols, in lexical order</param> + public Rule(int left, int[] right) + { + this.LeftHandSide = left; + this.RightHandSide = right; + } + } + + /// <summary> + /// Stack utility for the shift-reduce parser. + /// GPPG parsers have three instances: + /// (1) The parser state stack, T = QUT.Gppg.State, + /// (2) The semantic value stack, T = TValue, + /// (3) The location stack, T = TSpan. + /// </summary> + /// <typeparam name="T"></typeparam> +#if EXPORT_GPPG + public class PushdownPrefixState<T> +#else + internal class PushdownPrefixState<T> +#endif + { + // Note that we cannot use the BCL Stack<T> class + // here as derived types need to index into stacks. + // + private T[] array = new T[8]; + private int tos = 0; + + /// <summary> + /// Indexer for values of the stack below the top. + /// </summary> + /// <param name="index">index of the element, starting from the bottom</param> + /// <returns>the selected element</returns> + public T this[int index] { get { return array[index]; } } + + /// <summary> + /// The current depth of the stack. + /// </summary> + public int Depth { get { return tos; } } + + internal void Push(T value) + { + if (tos >= array.Length) + { + T[] newarray = new T[array.Length * 2]; + System.Array.Copy(array, newarray, tos); + array = newarray; + } + array[tos++] = value; + } + + internal T Pop() + { + T rslt = array[--tos]; + array[tos] = default(T); + return rslt; + } + + internal T TopElement() { return array[tos - 1]; } + + internal bool IsEmpty() { return tos == 0; } + } +} \ No newline at end of file diff --git a/Module8/SimpleLanguage3/SimpleLang3.csproj b/Module8/SimpleLanguage3/SimpleLang3.csproj new file mode 100644 index 0000000..c189535 --- /dev/null +++ b/Module8/SimpleLanguage3/SimpleLang3.csproj @@ -0,0 +1,68 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>SimpleLang</RootNamespace> + <AssemblyName>SimpleLang</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Visitors\AssignCountVisitor.cs" /> + <Compile Include="Visitors\AutoVisitor.cs" /> + <Compile Include="Visitors\GenCodeVisitors\GenCodeVisitor.cs" /> + <Compile Include="Visitors\GenCodeVisitors\GenCodeCreator.cs" /> + <Compile Include="Visitors\PrettyPrintVisitor.cs" /> + <Compile Include="Visitors\Visitor.cs" /> + <Compile Include="Main.cs" /> + <Compile Include="ParserHelper.cs" /> + <Compile Include="ProgramTree.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="ShiftReduceParserCode.cs" /> + <Compile Include="SimpleLex.cs" /> + <Compile Include="SimpleYacc.cs" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project> \ No newline at end of file diff --git a/Module8/SimpleLanguage3/SimpleLang3.sln b/Module8/SimpleLanguage3/SimpleLang3.sln new file mode 100644 index 0000000..091c760 --- /dev/null +++ b/Module8/SimpleLanguage3/SimpleLang3.sln @@ -0,0 +1,22 @@ +п»ї +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleLang3", "SimpleLang3.csproj", "{12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Debug|x86.ActiveCfg = Debug|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Debug|x86.Build.0 = Debug|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Release|x86.ActiveCfg = Release|x86 + {12B9D996-7B4A-4EE4-9AD8-2E24EAF3F574}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Module8/SimpleLanguage3/SimpleLex.cs b/Module8/SimpleLanguage3/SimpleLex.cs new file mode 100644 index 0000000..e20b477 --- /dev/null +++ b/Module8/SimpleLanguage3/SimpleLex.cs @@ -0,0 +1,1531 @@ +// +// This CSharp output file generated by Gardens Point LEX +// Version: 1.1.3.301 +// Machine: HUB +// DateTime: 21.09.2017 21:02:17 +// UserName: someone +// GPLEX input file <SimpleLex.lex> +// GPLEX frame file <embedded resource> +// +// Option settings: unicode, parser, minimize +// Option settings: classes, compressMap, compressNext, persistBuffer, embedbuffers +// Fallback code page: Target machine default +// + +// +// Experimental embedded frame +// Version 1.1.3 of 18-April-2010 +// +// +#define BACKUP +#define PERSIST + +using System; +using System.IO; +using System.Text; +using System.Globalization; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; + +using SimpleParser; +using QUT.Gppg; +using System.Linq; + +namespace SimpleScanner +{ + /// <summary> + /// Summary Canonical example of GPLEX automaton + /// </summary> + +#if STANDALONE + // + // These are the dummy declarations for stand-alone GPLEX applications + // normally these declarations would come from the parser. + // If you declare /noparser, or %option noparser then you get this. + // + + public enum Tokens + { + EOF = 0, maxParseToken = int.MaxValue + // must have at least these two, values are almost arbitrary + } + + public abstract class ScanBase + { + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + public abstract int yylex(); + + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yywrap")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yywrap")] + protected virtual bool yywrap() { return true; } + +#if BABEL + protected abstract int CurrentSc { get; set; } + // EolState is the 32-bit of state data persisted at + // the end of each line for Visual Studio colorization. + // The default is to return CurrentSc. You must override + // this if you want more complicated behavior. + public virtual int EolState { + get { return CurrentSc; } + set { CurrentSc = value; } + } + } + + public interface IColorScan + { + void SetSource(string source, int offset); + int GetNext(ref int state, out int start, out int end); +#endif // BABEL + } + +#endif // STANDALONE + + // If the compiler can't find the scanner base class maybe you + // need to run GPPG with the /gplex option, or GPLEX with /noparser +#if BABEL + public sealed partial class Scanner : ScanBase, IColorScan + { + private ScanBuff buffer; + int currentScOrd; // start condition ordinal + + protected override int CurrentSc + { + // The current start state is a property + // to try to avoid the user error of setting + // scState but forgetting to update the FSA + // start state "currentStart" + // + get { return currentScOrd; } // i.e. return YY_START; + set { currentScOrd = value; // i.e. BEGIN(value); + currentStart = startState[value]; } + } +#else // BABEL + public sealed partial class Scanner : ScanBase + { + private ScanBuff buffer; + int currentScOrd; // start condition ordinal +#endif // BABEL + + /// <summary> + /// The input buffer for this scanner. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public ScanBuff Buffer { get { return buffer; } } + + private static int GetMaxParseToken() { + System.Reflection.FieldInfo f = typeof(Tokens).GetField("maxParseToken"); + return (f == null ? int.MaxValue : (int)f.GetValue(null)); + } + + static int parserMax = GetMaxParseToken(); + + enum Result {accept, noMatch, contextFound}; + + const int maxAccept = 17; + const int initial = 18; + const int eofNum = 0; + const int goStart = -1; + const int INITIAL = 0; + +#region user code +#endregion user code + + int state; + int currentStart = startState[0]; + int code; // last code read + int cCol; // column number of code + int lNum; // current line number + // + // The following instance variables are used, among other + // things, for constructing the yylloc location objects. + // + int tokPos; // buffer position at start of token + int tokCol; // zero-based column number at start of token + int tokLin; // line number at start of token + int tokEPos; // buffer position at end of token + int tokECol; // column number at end of token + int tokELin; // line number at end of token + string tokTxt; // lazily constructed text of token +#if STACK + private Stack<int> scStack = new Stack<int>(); +#endif // STACK + +#region ScannerTables + struct Table { + public int min; public int rng; public int dflt; + public sbyte[] nxt; + public Table(int m, int x, int d, sbyte[] n) { + min = m; rng = x; dflt = d; nxt = n; + } + }; + + static int[] startState = new int[] {18, 0}; + +#region CompressedCharacterMap + // + // There are 15 equivalence classes + // There are 2 character sequence regions + // There are 1 tables, 123 entries + // There are 1 runs, 0 singletons + // Decision tree depth is 1 + // + static sbyte[] mapC0 = new sbyte[123] { +/* '\0' */ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 0, 14, 14, +/* '\x10' */ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +/* '\x20' */ 0, 14, 14, 14, 14, 14, 14, 14, 11, 12, 9, 8, 13, 7, 2, 10, +/* '0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 6, 14, 5, 14, 14, +/* '@' */ 14, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* 'P' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 14, 14, 14, 14, 3, +/* '`' */ 14, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* 'p' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; + + static sbyte MapC(int code) + { // '\0' <= code <= '\U0010FFFF' + if (code < 123) // '\0' <= code <= 'z' + return mapC0[code - 0]; + else // '{' <= code <= '\U0010FFFF' + return (sbyte)14; + } +#endregion + + static Table[] NxS = new Table[20] { +/* NxS[ 0] */ new Table(0, 0, 0, null), +/* NxS[ 1] */ new Table(1, 2, -1, new sbyte[] {1, 19}), +/* NxS[ 2] */ new Table(0, 0, -1, null), +/* NxS[ 3] */ new Table(1, 3, -1, new sbyte[] {3, -1, 3}), +/* NxS[ 4] */ new Table(5, 1, -1, new sbyte[] {16}), +/* NxS[ 5] */ new Table(0, 0, -1, null), +/* NxS[ 6] */ new Table(5, 1, -1, new sbyte[] {15}), +/* NxS[ 7] */ new Table(5, 1, -1, new sbyte[] {14}), +/* NxS[ 8] */ new Table(5, 1, -1, new sbyte[] {13}), +/* NxS[ 9] */ new Table(0, 0, -1, null), +/* NxS[ 10] */ new Table(0, 0, -1, null), +/* NxS[ 11] */ new Table(0, 0, -1, null), +/* NxS[ 12] */ new Table(0, 0, -1, null), +/* NxS[ 13] */ new Table(0, 0, -1, null), +/* NxS[ 14] */ new Table(0, 0, -1, null), +/* NxS[ 15] */ new Table(0, 0, -1, null), +/* NxS[ 16] */ new Table(0, 0, -1, null), +/* NxS[ 17] */ new Table(1, 1, -1, new sbyte[] {17}), +/* NxS[ 18] */ new Table(1, 14, -1, new sbyte[] {1, 2, 3, 4, 2, 5, + 6, 7, 8, 9, 10, 11, 12, 2}), +/* NxS[ 19] */ new Table(1, 1, -1, new sbyte[] {17}), + }; + +int NextState() { + if (code == ScanBuff.EndOfFile) + return eofNum; + else + unchecked { + int rslt; + int idx = MapC(code) - NxS[state].min; + if (idx < 0) idx += 15; + if ((uint)idx >= (uint)NxS[state].rng) rslt = NxS[state].dflt; + else rslt = NxS[state].nxt[idx]; + return rslt; + } +} + +#endregion + + +#if BACKUP + // ============================================================== + // == Nested struct used for backup in automata that do backup == + // ============================================================== + + struct Context // class used for automaton backup. + { + public int bPos; + public int rPos; // scanner.readPos saved value + public int cCol; + public int lNum; // Need this in case of backup over EOL. + public int state; + public int cChr; + } + + private Context ctx = new Context(); +#endif // BACKUP + + // ============================================================== + // ==== Nested struct to support input switching in scanners ==== + // ============================================================== + + struct BufferContext { + internal ScanBuff buffSv; + internal int chrSv; + internal int cColSv; + internal int lNumSv; + } + + // ============================================================== + // ===== Private methods to save and restore buffer contexts ==== + // ============================================================== + + /// <summary> + /// This method creates a buffer context record from + /// the current buffer object, together with some + /// scanner state values. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + BufferContext MkBuffCtx() + { + BufferContext rslt; + rslt.buffSv = this.buffer; + rslt.chrSv = this.code; + rslt.cColSv = this.cCol; + rslt.lNumSv = this.lNum; + return rslt; + } + + /// <summary> + /// This method restores the buffer value and allied + /// scanner state from the given context record value. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void RestoreBuffCtx(BufferContext value) + { + this.buffer = value.buffSv; + this.code = value.chrSv; + this.cCol = value.cColSv; + this.lNum = value.lNumSv; + } + // =================== End Nested classes ======================= + +#if !NOFILES + public Scanner(Stream file) { + SetSource(file, 0); // unicode option + } + + public Scanner(Stream file, string codepage) { + SetSource(file, CodePageHandling.GetCodePage(codepage)); + } + +#endif // !NOFILES + + public Scanner() { } + + private int readPos; + + void GetCode() + { + if (code == '\n') // This needs to be fixed for other conventions + // i.e. [\r\n\205\u2028\u2029] + { + cCol = -1; + lNum++; + } + readPos = buffer.Pos; + + // Now read new codepoint. + code = buffer.Read(); + if (code > ScanBuff.EndOfFile) + { +#if (!BYTEMODE) + if (code >= 0xD800 && code <= 0xDBFF) + { + int next = buffer.Read(); + if (next < 0xDC00 || next > 0xDFFF) + code = ScanBuff.UnicodeReplacementChar; + else + code = (0x10000 + (code & 0x3FF << 10) + (next & 0x3FF)); + } +#endif + cCol++; + } + } + + void MarkToken() + { +#if (!PERSIST) + buffer.Mark(); +#endif + tokPos = readPos; + tokLin = lNum; + tokCol = cCol; + } + + void MarkEnd() + { + tokTxt = null; + tokEPos = readPos; + tokELin = lNum; + tokECol = cCol; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int Peek() + { + int rslt, codeSv = code, cColSv = cCol, lNumSv = lNum, bPosSv = buffer.Pos; + GetCode(); rslt = code; + lNum = lNumSv; cCol = cColSv; code = codeSv; buffer.Pos = bPosSv; + return rslt; + } + + // ============================================================== + // ===== Initialization of string-based input buffers ==== + // ============================================================== + + /// <summary> + /// Create and initialize a StringBuff buffer object for this scanner + /// </summary> + /// <param name="source">the input string</param> + /// <param name="offset">starting offset in the string</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(string source, int offset) + { + this.buffer = ScanBuff.GetBuffer(source); + this.buffer.Pos = offset; + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } + +#if !NOFILES + // ================ LineBuffer Initialization =================== + + /// <summary> + /// Create and initialize a LineBuff buffer object for this scanner + /// </summary> + /// <param name="source">the list of input strings</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(IList<string> source) + { + this.buffer = ScanBuff.GetBuffer(source); + this.code = '\n'; // to initialize yyline, yycol and lineStart + this.lNum = 0; + GetCode(); + } + + // =============== StreamBuffer Initialization ================== + + /// <summary> + /// Create and initialize a StreamBuff buffer object for this scanner. + /// StreamBuff is buffer for 8-bit byte files. + /// </summary> + /// <param name="source">the input byte stream</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(Stream source) + { + this.buffer = ScanBuff.GetBuffer(source); + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } + +#if !BYTEMODE + // ================ TextBuffer Initialization =================== + + /// <summary> + /// Create and initialize a TextBuff buffer object for this scanner. + /// TextBuff is a buffer for encoded unicode files. + /// </summary> + /// <param name="source">the input text file</param> + /// <param name="fallbackCodePage">Code page to use if file has + /// no BOM. For 0, use machine default; for -1, 8-bit binary</param> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void SetSource(Stream source, int fallbackCodePage) + { + this.buffer = ScanBuff.GetBuffer(source, fallbackCodePage); + this.lNum = 0; + this.code = '\n'; // to initialize yyline, yycol and lineStart + GetCode(); + } +#endif // !BYTEMODE +#endif // !NOFILES + + // ============================================================== + +#if BABEL + // + // Get the next token for Visual Studio + // + // "state" is the inout mode variable that maintains scanner + // state between calls, using the EolState property. In principle, + // if the calls of EolState are costly set could be called once + // only per line, at the start; and get called only at the end + // of the line. This needs more infrastructure ... + // + public int GetNext(ref int state, out int start, out int end) + { + Tokens next; + int s, e; + s = state; // state at start + EolState = state; + next = (Tokens)Scan(); + state = EolState; + e = state; // state at end; + start = tokPos; + end = tokEPos - 1; // end is the index of last char. + return (int)next; + } +#endif // BABEL + + // ======== AbstractScanner<> Implementation ========= + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yylex")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yylex")] + public override int yylex() + { + // parserMax is set by reflecting on the Tokens + // enumeration. If maxParseToken is defined + // that is used, otherwise int.MaxValue is used. + int next; + do { next = Scan(); } while (next >= parserMax); + return next; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yypos { get { return tokPos; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yyline { get { return tokLin; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + int yycol { get { return tokCol; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yytext")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yytext")] + public string yytext + { + get + { + if (tokTxt == null) + tokTxt = buffer.GetString(tokPos, tokEPos); + return tokTxt; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void yyless(int n) + { + buffer.Pos = tokPos; + // Must read at least one char, so set before start. + cCol = tokCol - 1; + GetCode(); + // Now ensure that line counting is correct. + lNum = tokLin; + // And count the rest of the text. + for (int i = 0; i < n; i++) GetCode(); + MarkEnd(); + } + + // + // It would be nice to count backward in the text + // but it does not seem possible to re-establish + // the correct column counts except by going forward. + // + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + void _yytrunc(int n) { yyless(yyleng - n); } + + // + // This is painful, but we no longer count + // codepoints. For the overwhelming majority + // of cases the single line code is fast, for + // the others, well, at least it is all in the + // buffer so no files are touched. Note that we + // can't use (tokEPos - tokPos) because of the + // possibility of surrogate pairs in the token. + // + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "yyleng")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "yyleng")] + public int yyleng + { + get { +#if BYTEMODE + return tokEPos - tokPos; +#else + if (tokELin == tokLin) + return tokECol - tokCol; + else { + int ch; + int count = 0; + int save = buffer.Pos; + buffer.Pos = tokPos; + do { + ch = buffer.Read(); + if (!char.IsHighSurrogate((char)ch)) count++; + } while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile); + buffer.Pos = save; + return count; + } +#endif // BYTEMODE + } + } + + // ============ methods available in actions ============== + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal int YY_START { + get { return currentScOrd; } + set { currentScOrd = value; + currentStart = startState[value]; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void BEGIN(int next) { + currentScOrd = next; + currentStart = startState[next]; + } + + // ============== The main tokenizer code ================= + + int Scan() + { + try { + for (; ; ) + { + int next; // next state to enter +#if BACKUP + Result rslt = Result.noMatch; +#endif // BACKUP +#if LEFTANCHORS + for (;;) + { + // Discard characters that do not start any pattern. + // Must check the left anchor condition after *every* GetCode! + state = ((cCol == 0) ? anchorState[currentScOrd] : currentStart); + if ((next = NextState()) != goStart) + break; // LOOP EXIT HERE... + GetCode(); + } + +#else // !LEFTANCHORS + state = currentStart; + while ((next = NextState()) == goStart) + // At this point, the current character has no + // transition from the current state. We discard + // the "no-match" char. In traditional LEX such + // characters are echoed to the console. + GetCode(); +#endif // LEFTANCHORS + // At last, a valid transition ... + MarkToken(); + state = next; + GetCode(); + + while ((next = NextState()) > eofNum) // Exit for goStart AND for eofNum +#if BACKUP + if (state <= maxAccept && next > maxAccept) // need to prepare backup data + { + // ctx is an object. The fields may be + // mutated by the call to Recurse2. + // On return the data in ctx is the + // *latest* accept state that was found. + + rslt = Recurse2(ref ctx, next); + if (rslt == Result.noMatch) + RestoreStateAndPos(ref ctx); + break; + } + else +#endif // BACKUP + { + state = next; + GetCode(); + } + if (state <= maxAccept) + { + MarkEnd(); +#region ActionSwitch +#pragma warning disable 162 + switch (state) + { + case eofNum: + if (yywrap()) + return (int)Tokens.EOF; + break; + case 1: +yylval.iVal = int.Parse(yytext); + return (int)Tokens.INUM; + break; + case 2: + case 4: +LexError(); + break; + case 3: +int res = ScannerHelper.GetIDToken(yytext); + if (res == (int)Tokens.ID) + yylval.sVal = yytext; + return res; + break; + case 5: +return (int)Tokens.SEMICOLON; + break; + case 6: +return (int)Tokens.MINUS; + break; + case 7: +return (int)Tokens.PLUS; + break; + case 8: +return (int)Tokens.MULT; + break; + case 9: +return (int)Tokens.DIV; + break; + case 10: +return (int)Tokens.LPAREN; + break; + case 11: +return (int)Tokens.RPAREN; + break; + case 12: +return (int)Tokens.COLUMN; + break; + case 13: +return (int)Tokens.ASSIGNMULT; + break; + case 14: +return (int)Tokens.ASSIGNPLUS; + break; + case 15: +return (int)Tokens.ASSIGNMINUS; + break; + case 16: +return (int)Tokens.ASSIGN; + break; + case 17: +yylval.dVal = double.Parse(yytext); + return (int)Tokens.RNUM; + break; + default: + break; + } +#pragma warning restore 162 +#endregion + } + } + } // end try + finally { +// User-specified epilog to scan() +yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); +// End, user-specified epilog + } // end finally + } + +#if BACKUP + Result Recurse2(ref Context ctx, int next) + { + // Assert: at entry "state" is an accept state AND + // NextState(state, code) != goStart AND + // NextState(state, code) is not an accept state. + // + SaveStateAndPos(ref ctx); + state = next; + GetCode(); + + while ((next = NextState()) > eofNum) + { + if (state <= maxAccept && next > maxAccept) // need to update backup data + SaveStateAndPos(ref ctx); + state = next; + if (state == eofNum) return Result.accept; + GetCode(); + } + return (state <= maxAccept ? Result.accept : Result.noMatch); + } + + void SaveStateAndPos(ref Context ctx) + { + ctx.bPos = buffer.Pos; + ctx.rPos = readPos; + ctx.cCol = cCol; + ctx.lNum = lNum; + ctx.state = state; + ctx.cChr = code; + } + + void RestoreStateAndPos(ref Context ctx) + { + buffer.Pos = ctx.bPos; + readPos = ctx.rPos; + cCol = ctx.cCol; + lNum = ctx.lNum; + state = ctx.state; + code = ctx.cChr; + } + +#endif // BACKUP + + // ============= End of the tokenizer code ================ + +#if STACK + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void yy_clear_stack() { scStack.Clear(); } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal int yy_top_state() { return scStack.Peek(); } + + internal void yy_push_state(int state) + { + scStack.Push(currentScOrd); + BEGIN(state); + } + + internal void yy_pop_state() + { + // Protect against input errors that pop too far ... + if (scStack.Count > 0) { + int newSc = scStack.Pop(); + BEGIN(newSc); + } // Otherwise leave stack unchanged. + } + #endif // STACK + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal void ECHO() { Console.Out.Write(yytext); } + +#region UserCodeSection + +public override void yyerror(string format, params object[] args) // обработка синтаксических ошибок +{ + var ww = args.Skip(1).Cast<string>().ToArray(); + string errorMsg = string.Format("({0},{1}): Встречено {2}, а ожидалось {3}", yyline, yycol, args[0], string.Join(" или ", ww)); + throw new SyntaxException(errorMsg); +} + +public void LexError() +{ + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); + throw new LexException(errorMsg); +} + +class ScannerHelper +{ + private static Dictionary<string,int> keywords; + + static ScannerHelper() + { + keywords = new Dictionary<string,int>(); + keywords.Add("begin",(int)Tokens.BEGIN); + keywords.Add("end",(int)Tokens.END); + keywords.Add("cycle",(int)Tokens.CYCLE); + keywords.Add("write",(int)Tokens.WRITE); + keywords.Add("var",(int)Tokens.VAR); + } + public static int GetIDToken(string s) + { + if (keywords.ContainsKey(s.ToLower())) + return keywords[s]; + else + return (int)Tokens.ID; + } + +} + +#endregion + } // end class $Scanner + +// ============================================================== +// <auto-generated> +// This code automatically produced from an embedded resource. +// Do not edit this file, or it will become incompatible with +// the specification from which it was generated. +// </auto-generated> +// ============================================================== + +// Code copied from GPLEX embedded resource + [Serializable] + public class BufferException : Exception + { + public BufferException() { } + public BufferException(string message) : base(message) { } + public BufferException(string message, Exception innerException) + : base(message, innerException) { } + protected BufferException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + } + + public abstract class ScanBuff + { + private string fileNm; + + public const int EndOfFile = -1; + public const int UnicodeReplacementChar = 0xFFFD; + + public bool IsFile { get { return (fileNm != null); } } + public string FileName { get { return fileNm; } set { fileNm = value; } } + + public abstract int Pos { get; set; } + public abstract int Read(); + public virtual void Mark() { } + + public abstract string GetString(int begin, int limit); + + public static ScanBuff GetBuffer(string source) + { + return new StringBuffer(source); + } + + public static ScanBuff GetBuffer(IList<string> source) + { + return new LineBuffer(source); + } + + public static ScanBuff GetBuffer(Stream source) + { + return new BuildBuffer(source); + } + +#if (!BYTEMODE) + public static ScanBuff GetBuffer(Stream source, int fallbackCodePage) + { + return new BuildBuffer(source, fallbackCodePage); + } +#endif + } + + #region Buffer classes + + // ============================================================== + // ===== Definitions for various ScanBuff derived classes ==== + // ============================================================== + // =============== String input ================ + // ============================================================== + + /// <summary> + /// This class reads characters from a single string as + /// required, for example, by Visual Studio language services + /// </summary> + sealed class StringBuffer : ScanBuff + { + string str; // input buffer + int bPos; // current position in buffer + int sLen; + + public StringBuffer(string source) + { + this.str = source; + this.sLen = source.Length; + this.FileName = null; + } + + public override int Read() + { + if (bPos < sLen) return str[bPos++]; + else if (bPos == sLen) { bPos++; return '\n'; } // one strike, see new line + else { bPos++; return EndOfFile; } // two strikes and you're out! + } + + public override string GetString(int begin, int limit) + { + // "limit" can be greater than sLen with the BABEL + // option set. Read returns a "virtual" EOL if + // an attempt is made to read past the end of the + // string buffer. Without the guard any attempt + // to fetch yytext for a token that includes the + // EOL will throw an index exception. + if (limit > sLen) limit = sLen; + if (limit <= begin) return ""; + else return str.Substring(begin, limit - begin); + } + + public override int Pos + { + get { return bPos; } + set { bPos = value; } + } + + public override string ToString() { return "StringBuffer"; } + } + + // ============================================================== + // The LineBuff class contributed by Nigel Horspool, + // nigelh@cs.uvic.cs + // ============================================================== + + sealed class LineBuffer : ScanBuff + { + IList<string> line; // list of source lines from a file + int numLines; // number of strings in line list + string curLine; // current line in that list + int cLine; // index of current line in the list + int curLen; // length of current line + int curLineStart; // position of line start in whole file + int curLineEnd; // position of line end in whole file + int maxPos; // max position ever visited in whole file + int cPos; // ordinal number of code in source + + // Constructed from a list of strings, one per source line. + // The lines have had trailing '\n' characters removed. + public LineBuffer(IList<string> lineList) + { + line = lineList; + numLines = line.Count; + cPos = curLineStart = 0; + curLine = (numLines > 0 ? line[0] : ""); + maxPos = curLineEnd = curLen = curLine.Length; + cLine = 1; + FileName = null; + } + + public override int Read() + { + if (cPos < curLineEnd) + return curLine[cPos++ - curLineStart]; + if (cPos++ == curLineEnd) + return '\n'; + if (cLine >= numLines) + return EndOfFile; + curLine = line[cLine]; + curLen = curLine.Length; + curLineStart = curLineEnd + 1; + curLineEnd = curLineStart + curLen; + if (curLineEnd > maxPos) + maxPos = curLineEnd; + cLine++; + return curLen > 0 ? curLine[0] : '\n'; + } + + // To speed up searches for the line containing a position + private int cachedPosition; + private int cachedIxdex; + private int cachedLineStart; + + // Given a position pos within the entire source, the results are + // ix -- the index of the containing line + // lstart -- the position of the first character on that line + private void findIndex(int pos, out int ix, out int lstart) + { + if (pos >= cachedPosition) + { + ix = cachedIxdex; lstart = cachedLineStart; + } + else + { + ix = lstart = 0; + } + for (; ; ) + { + int len = line[ix].Length + 1; + if (pos < lstart + len) break; + lstart += len; + ix++; + } + cachedPosition = pos; + cachedIxdex = ix; + cachedLineStart = lstart; + } + + public override string GetString(int begin, int limit) + { + if (begin >= maxPos || limit <= begin) return ""; + int endIx, begIx, endLineStart, begLineStart; + findIndex(begin, out begIx, out begLineStart); + int begCol = begin - begLineStart; + findIndex(limit, out endIx, out endLineStart); + int endCol = limit - endLineStart; + string s = line[begIx]; + if (begIx == endIx) + { + // the usual case, substring all on one line + return (endCol <= s.Length) ? + s.Substring(begCol, endCol - begCol) + : s.Substring(begCol) + "\n"; + } + // the string spans multiple lines, yuk! + StringBuilder sb = new StringBuilder(); + if (begCol < s.Length) + sb.Append(s.Substring(begCol)); + for (; ; ) + { + sb.Append("\n"); + s = line[++begIx]; + if (begIx >= endIx) break; + sb.Append(s); + } + if (endCol <= s.Length) + { + sb.Append(s.Substring(0, endCol)); + } + else + { + sb.Append(s); + sb.Append("\n"); + } + return sb.ToString(); + } + + public override int Pos + { + get { return cPos; } + set + { + cPos = value; + findIndex(cPos, out cLine, out curLineStart); + curLine = line[cLine]; + curLineEnd = curLineStart + curLine.Length; + } + } + + public override string ToString() { return "LineBuffer"; } + } + + + // ============================================================== + // ===== class BuildBuff : for unicode text files ======== + // ============================================================== + + class BuildBuffer : ScanBuff + { + // Double buffer for char stream. + class BufferElement + { + StringBuilder bldr = new StringBuilder(); + StringBuilder next = new StringBuilder(); + int minIx; + int maxIx; + int brkIx; + bool appendToNext; + + internal BufferElement() { } + + internal int MaxIndex { get { return maxIx; } } + // internal int MinIndex { get { return minIx; } } + + internal char this[int index] + { + get + { + if (index < minIx || index >= maxIx) + throw new BufferException("Index was outside data buffer"); + else if (index < brkIx) + return bldr[index - minIx]; + else + return next[index - brkIx]; + } + } + + internal void Append(char[] block, int count) + { + maxIx += count; + if (appendToNext) + this.next.Append(block, 0, count); + else + { + this.bldr.Append(block, 0, count); + brkIx = maxIx; + appendToNext = true; + } + } + + internal string GetString(int start, int limit) + { + if (limit <= start) + return ""; + if (start >= minIx && limit <= maxIx) + if (limit < brkIx) // String entirely in bldr builder + return bldr.ToString(start - minIx, limit - start); + else if (start >= brkIx) // String entirely in next builder + return next.ToString(start - brkIx, limit - start); + else // Must do a string-concatenation + return + bldr.ToString(start - minIx, brkIx - start) + + next.ToString(0, limit - brkIx); + else + throw new BufferException("String was outside data buffer"); + } + + internal void Mark(int limit) + { + if (limit > brkIx + 16) // Rotate blocks + { + StringBuilder temp = bldr; + bldr = next; + next = temp; + next.Length = 0; + minIx = brkIx; + brkIx = maxIx; + } + } + } + + BufferElement data = new BufferElement(); + + int bPos; // Postion index in the StringBuilder + BlockReader NextBlk; // Delegate that serves char-arrays; + + private string EncodingName + { + get + { + StreamReader rdr = NextBlk.Target as StreamReader; + return (rdr == null ? "raw-bytes" : rdr.CurrentEncoding.BodyName); + } + } + + public BuildBuffer(Stream stream) + { + FileStream fStrm = (stream as FileStream); + if (fStrm != null) FileName = fStrm.Name; + NextBlk = BlockReaderFactory.Raw(stream); + } + +#if (!BYTEMODE) + public BuildBuffer(Stream stream, int fallbackCodePage) + { + FileStream fStrm = (stream as FileStream); + if (fStrm != null) FileName = fStrm.Name; + NextBlk = BlockReaderFactory.Get(stream, fallbackCodePage); + } +#endif + + /// <summary> + /// Marks a conservative lower bound for the buffer, + /// allowing space to be reclaimed. If an application + /// needs to call GetString at arbitrary past locations + /// in the input stream, Mark() is not called. + /// </summary> + public override void Mark() { data.Mark(bPos - 2); } + + public override int Pos + { + get { return bPos; } + set { bPos = value; } + } + + + /// <summary> + /// Read returns the ordinal number of the next char, or + /// EOF (-1) for an end of stream. Note that the next + /// code point may require *two* calls of Read(). + /// </summary> + /// <returns></returns> + public override int Read() + { + // + // Characters at positions + // [data.offset, data.offset + data.bldr.Length) + // are available in data.bldr. + // + if (bPos < data.MaxIndex) + { + // ch0 cannot be EOF + return (int)data[bPos++]; + } + else // Read from underlying stream + { + // Experimental code, blocks of page size + char[] chrs = new char[4096]; + int count = NextBlk(chrs, 0, 4096); + if (count == 0) + return EndOfFile; + else + { + data.Append(chrs, count); + return (int)data[bPos++]; + } + } + } + + public override string GetString(int begin, int limit) + { + return data.GetString(begin, limit); + } + + public override string ToString() + { + return "StringBuilder buffer, encoding: " + this.EncodingName; + } + } + + // =============== End ScanBuff-derived classes ================== + + public delegate int BlockReader(char[] block, int index, int number); + + // A delegate factory, serving up a delegate that + // reads a block of characters from the underlying + // encoded stream, via a StreamReader object. + // + public static class BlockReaderFactory + { + public static BlockReader Raw(Stream stream) + { + return delegate(char[] block, int index, int number) + { + byte[] b = new byte[number]; + int count = stream.Read(b, 0, number); + int i = 0; + int j = index; + for (; i < count; i++, j++) + block[j] = (char)b[i]; + return count; + }; + } + +#if (!BYTEMODE) + public static BlockReader Get(Stream stream, int fallbackCodePage) + { + Encoding encoding; + int preamble = Preamble(stream); + + if (preamble != 0) // There is a valid BOM here! + encoding = Encoding.GetEncoding(preamble); + else if (fallbackCodePage == -1) // Fallback is "raw" bytes + return Raw(stream); + else if (fallbackCodePage != -2) // Anything but "guess" + encoding = Encoding.GetEncoding(fallbackCodePage); + else // This is the "guess" option + { + int guess = new Guesser(stream).GuessCodePage(); + stream.Seek(0, SeekOrigin.Begin); + if (guess == -1) // ==> this is a 7-bit file + encoding = Encoding.ASCII; + else if (guess == 65001) + encoding = Encoding.UTF8; + else // ==> use the machine default + encoding = Encoding.Default; + } + StreamReader reader = new StreamReader(stream, encoding); + return reader.Read; + } + + static int Preamble(Stream stream) + { + int b0 = stream.ReadByte(); + int b1 = stream.ReadByte(); + + if (b0 == 0xfe && b1 == 0xff) + return 1201; // UTF16BE + if (b0 == 0xff && b1 == 0xfe) + return 1200; // UTF16LE + + int b2 = stream.ReadByte(); + if (b0 == 0xef && b1 == 0xbb && b2 == 0xbf) + return 65001; // UTF8 + // + // There is no unicode preamble, so we + // return denoter for the machine default. + // + stream.Seek(0, SeekOrigin.Begin); + return 0; + } +#endif // !BYTEMODE + } + #endregion Buffer classes + + // ============================================================== + // ============ class CodePageHandling ============= + // ============================================================== + + public static class CodePageHandling + { + public static int GetCodePage(string option) + { + string command = option.ToUpperInvariant(); + if (command.StartsWith("CodePage:", StringComparison.OrdinalIgnoreCase)) + command = command.Substring(9); + try + { + if (command.Equals("RAW")) + return -1; + else if (command.Equals("GUESS")) + return -2; + else if (command.Equals("DEFAULT")) + return 0; + else if (char.IsDigit(command[0])) + return int.Parse(command, CultureInfo.InvariantCulture); + else + { + Encoding enc = Encoding.GetEncoding(command); + return enc.CodePage; + } + } + catch (FormatException) + { + Console.Error.WriteLine( + "Invalid format \"{0}\", using machine default", option); + } + catch (ArgumentException) + { + Console.Error.WriteLine( + "Unknown code page \"{0}\", using machine default", option); + } + return 0; + } + } +#region guesser +#if (!BYTEMODE) + // ============================================================== + // ============ Encoding Guesser ============= + // ============================================================== + + /// <summary> + /// This class provides a simple finite state automaton that + /// scans the file looking for (1) valid UTF-8 byte patterns, + /// (2) bytes >= 0x80 which are not part of a UTF-8 sequence. + /// The method then guesses whether it is UTF-8 or maybe some + /// local machine default encoding. This works well for the + /// various Latin encodings. + /// </summary> + internal class Guesser + { + ScanBuff buffer; + + public int GuessCodePage() { return Scan(); } + + const int maxAccept = 10; + const int initial = 0; + const int eofNum = 0; + const int goStart = -1; + const int INITIAL = 0; + const int EndToken = 0; + + #region user code + /* + * Reads the bytes of a file to determine if it is + * UTF-8 or a single-byte code page file. + */ + public long utfX; + public long uppr; + #endregion user code + + int state; + int currentStart = startState[0]; + int code; + + #region ScannerTables + static int[] startState = new int[] { 11, 0 }; + + #region CharacterMap + static sbyte[] map = new sbyte[256] { +/* '\0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x10' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x20' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '0' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '@' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 'P' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '`' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 'p' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* '\x80' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\x90' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xA0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xB0' */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* '\xC0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* '\xD0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* '\xE0' */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +/* '\xF0' */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5 }; + #endregion + + static sbyte[][] nextState = new sbyte[][] { + new sbyte[] {0, 0, 0, 0, 0, 0}, + new sbyte[] {-1, -1, 10, -1, -1, -1}, + new sbyte[] {-1, -1, -1, -1, -1, -1}, + new sbyte[] {-1, -1, 8, -1, -1, -1}, + new sbyte[] {-1, -1, 5, -1, -1, -1}, + new sbyte[] {-1, -1, 6, -1, -1, -1}, + new sbyte[] {-1, -1, 7, -1, -1, -1}, + null, + new sbyte[] {-1, -1, 9, -1, -1, -1}, + null, + null, + new sbyte[] {-1, 1, 2, 3, 4, 2} + }; + + + [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + // Reason for suppression: cannot have self-reference in array initializer. + static Guesser() + { + nextState[7] = nextState[2]; + nextState[9] = nextState[2]; + nextState[10] = nextState[2]; + } + + int NextState() + { + if (code == ScanBuff.EndOfFile) + return eofNum; + else + return nextState[state][map[code]]; + } + #endregion + + public Guesser(System.IO.Stream file) { SetSource(file); } + + public void SetSource(System.IO.Stream source) + { + this.buffer = new BuildBuffer(source); + code = buffer.Read(); + } + + int Scan() + { + for (; ; ) + { + int next; + state = currentStart; + while ((next = NextState()) == goStart) + code = buffer.Read(); + + state = next; + code = buffer.Read(); + + while ((next = NextState()) > eofNum) + { + state = next; + code = buffer.Read(); + } + if (state <= maxAccept) + { + #region ActionSwitch +#pragma warning disable 162 + switch (state) + { + case eofNum: + switch (currentStart) + { + case 11: + if (utfX == 0 && uppr == 0) return -1; /* raw ascii */ + else if (uppr * 10 > utfX) return 0; /* default code page */ + else return 65001; /* UTF-8 encoding */ + break; + } + return EndToken; + case 1: // Recognized '{Upper128}', Shortest string "\xC0" + case 2: // Recognized '{Upper128}', Shortest string "\x80" + case 3: // Recognized '{Upper128}', Shortest string "\xE0" + case 4: // Recognized '{Upper128}', Shortest string "\xF0" + uppr++; + break; + case 5: // Recognized '{Utf8pfx4}{Utf8cont}', Shortest string "\xF0\x80" + uppr += 2; + break; + case 6: // Recognized '{Utf8pfx4}{Utf8cont}{2}', Shortest string "\xF0\x80\x80" + uppr += 3; + break; + case 7: // Recognized '{Utf8pfx4}{Utf8cont}{3}', Shortest string "\xF0\x80\x80\x80" + utfX += 3; + break; + case 8: // Recognized '{Utf8pfx3}{Utf8cont}', Shortest string "\xE0\x80" + uppr += 2; + break; + case 9: // Recognized '{Utf8pfx3}{Utf8cont}{2}', Shortest string "\xE0\x80\x80" + utfX += 2; + break; + case 10: // Recognized '{Utf8pfx2}{Utf8cont}', Shortest string "\xC0\x80" + utfX++; + break; + default: + break; + } +#pragma warning restore 162 + #endregion + } + } + } + } // end class Guesser + +#endif // !BYTEMODE +#endregion + +// End of code copied from embedded resource + +} // end namespace diff --git a/Module8/SimpleLanguage3/SimpleLex.lex b/Module8/SimpleLanguage3/SimpleLex.lex new file mode 100644 index 0000000..00dfa12 --- /dev/null +++ b/Module8/SimpleLanguage3/SimpleLex.lex @@ -0,0 +1,90 @@ +%using SimpleParser; +%using QUT.Gppg; +%using System.Linq; + +%namespace SimpleScanner + +Alpha [a-zA-Z_] +Digit [0-9] +AlphaDigit {Alpha}|{Digit} +INTNUM {Digit}+ +REALNUM {INTNUM}\.{INTNUM} +ID {Alpha}{AlphaDigit}* + +%% + +{INTNUM} { + yylval.iVal = int.Parse(yytext); + return (int)Tokens.INUM; +} + +{REALNUM} { + yylval.dVal = double.Parse(yytext); + return (int)Tokens.RNUM; +} + +{ID} { + int res = ScannerHelper.GetIDToken(yytext); + if (res == (int)Tokens.ID) + yylval.sVal = yytext; + return res; +} + +":=" { return (int)Tokens.ASSIGN; } +";" { return (int)Tokens.SEMICOLON; } +"-=" { return (int)Tokens.ASSIGNMINUS; } +"+=" { return (int)Tokens.ASSIGNPLUS; } +"*=" { return (int)Tokens.ASSIGNMULT; } +"+" { return (int)Tokens.PLUS; } +"-" { return (int)Tokens.MINUS; } +"*" { return (int)Tokens.MULT; } +"/" { return (int)Tokens.DIV; } +"(" { return (int)Tokens.LPAREN; } +")" { return (int)Tokens.RPAREN; } +"," { return (int)Tokens.COLUMN; } + +[^ \r\n] { + LexError(); +} + +%{ + yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); +%} + +%% + +public override void yyerror(string format, params object[] args) // обработка синтаксических ошибок +{ + var ww = args.Skip(1).Cast<string>().ToArray(); + string errorMsg = string.Format("({0},{1}): Встречено {2}, а ожидалось {3}", yyline, yycol, args[0], string.Join(" или ", ww)); + throw new SyntaxException(errorMsg); +} + +public void LexError() +{ + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); + throw new LexException(errorMsg); +} + +class ScannerHelper +{ + private static Dictionary<string,int> keywords; + + static ScannerHelper() + { + keywords = new Dictionary<string,int>(); + keywords.Add("begin",(int)Tokens.BEGIN); + keywords.Add("end",(int)Tokens.END); + keywords.Add("cycle",(int)Tokens.CYCLE); + keywords.Add("write",(int)Tokens.WRITE); + keywords.Add("var",(int)Tokens.VAR); + } + public static int GetIDToken(string s) + { + if (keywords.ContainsKey(s.ToLower())) + return keywords[s]; + else + return (int)Tokens.ID; + } + +} diff --git a/Module8/SimpleLanguage3/SimpleYacc.cs b/Module8/SimpleLanguage3/SimpleYacc.cs new file mode 100644 index 0000000..fa0d511 --- /dev/null +++ b/Module8/SimpleLanguage3/SimpleYacc.cs @@ -0,0 +1,274 @@ +// This code was generated by the Gardens Point Parser Generator +// Copyright (c) Wayne Kelly, QUT 2005-2010 +// (see accompanying GPPGcopyright.rtf) + +// GPPG version 1.3.6 +// Machine: HUB +// DateTime: 21.09.2017 21:02:18 +// UserName: someone +// Input file <SimpleYacc.y> + +// options: no-lines gplex + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using QUT.Gppg; +using System.IO; +using ProgramTree; + +namespace SimpleParser +{ +public enum Tokens { + error=1,EOF=2,BEGIN=3,END=4,CYCLE=5,ASSIGN=6, + ASSIGNPLUS=7,ASSIGNMINUS=8,ASSIGNMULT=9,SEMICOLON=10,WRITE=11,VAR=12, + PLUS=13,MINUS=14,MULT=15,DIV=16,LPAREN=17,RPAREN=18, + COLUMN=19,INUM=20,RNUM=21,ID=22}; + +public struct ValueType +{ + public double dVal; + public int iVal; + public string sVal; + public Node nVal; + public ExprNode eVal; + public StatementNode stVal; + public BlockNode blVal; + } +// Abstract base class for GPLEX scanners +public abstract class ScanBase : AbstractScanner<ValueType,LexLocation> { + private LexLocation __yylloc = new LexLocation(); + public override LexLocation yylloc { get { return __yylloc; } set { __yylloc = value; } } + protected virtual bool yywrap() { return true; } +} + +public class Parser: ShiftReduceParser<ValueType, LexLocation> +{ + // Verbatim content from SimpleYacc.y +// Эти объявления добавляются в класс GPPGParser, представляющий собой парсер, генерируемый системой gppg + public BlockNode root; // Корневой узел синтаксического дерева + public Parser(AbstractScanner<ValueType, LexLocation> scanner) : base(scanner) { } + private bool InDefSect = false; + // End verbatim content from SimpleYacc.y + +#pragma warning disable 649 + private static Dictionary<int, string> aliasses; +#pragma warning restore 649 + private static Rule[] rules = new Rule[30]; + private static State[] states = new State[48]; + private static string[] nonTerms = new string[] { + "progr", "expr", "ident", "T", "F", "statement", "assign", "block", "cycle", + "write", "empty", "var", "varlist", "stlist", "$accept", "Anon@1", }; + + static Parser() { + states[0] = new State(new int[]{3,4},new int[]{-1,1,-8,3}); + states[1] = new State(new int[]{2,2}); + states[2] = new State(-1); + states[3] = new State(-2); + states[4] = new State(new int[]{22,18,3,4,5,31,11,35,12,40,4,-11,10,-11},new int[]{-14,5,-6,47,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46}); + states[5] = new State(new int[]{4,6,10,7}); + states[6] = new State(-23); + states[7] = new State(new int[]{22,18,3,4,5,31,11,35,12,40,4,-11,10,-11},new int[]{-6,8,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46}); + states[8] = new State(-4); + states[9] = new State(-5); + states[10] = new State(new int[]{6,11}); + states[11] = new State(new int[]{22,18,20,19,17,20},new int[]{-2,12,-4,28,-5,27,-3,17}); + states[12] = new State(new int[]{13,13,14,23,4,-13,10,-13}); + states[13] = new State(new int[]{22,18,20,19,17,20},new int[]{-4,14,-5,27,-3,17}); + states[14] = new State(new int[]{15,15,16,25,13,-14,14,-14,4,-14,10,-14,18,-14,22,-14,3,-14,5,-14,11,-14,12,-14}); + states[15] = new State(new int[]{22,18,20,19,17,20},new int[]{-5,16,-3,17}); + states[16] = new State(-17); + states[17] = new State(-20); + states[18] = new State(-12); + states[19] = new State(-21); + states[20] = new State(new int[]{22,18,20,19,17,20},new int[]{-2,21,-4,28,-5,27,-3,17}); + states[21] = new State(new int[]{18,22,13,13,14,23}); + states[22] = new State(-22); + states[23] = new State(new int[]{22,18,20,19,17,20},new int[]{-4,24,-5,27,-3,17}); + states[24] = new State(new int[]{15,15,16,25,13,-15,14,-15,4,-15,10,-15,18,-15,22,-15,3,-15,5,-15,11,-15,12,-15}); + states[25] = new State(new int[]{22,18,20,19,17,20},new int[]{-5,26,-3,17}); + states[26] = new State(-18); + states[27] = new State(-19); + states[28] = new State(new int[]{15,15,16,25,13,-16,14,-16,4,-16,10,-16,18,-16,22,-16,3,-16,5,-16,11,-16,12,-16}); + states[29] = new State(-6); + states[30] = new State(-7); + states[31] = new State(new int[]{22,18,20,19,17,20},new int[]{-2,32,-4,28,-5,27,-3,17}); + states[32] = new State(new int[]{13,13,14,23,22,18,3,4,5,31,11,35,12,40,4,-11,10,-11},new int[]{-6,33,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46}); + states[33] = new State(-24); + states[34] = new State(-8); + states[35] = new State(new int[]{17,36}); + states[36] = new State(new int[]{22,18,20,19,17,20},new int[]{-2,37,-4,28,-5,27,-3,17}); + states[37] = new State(new int[]{18,38,13,13,14,23}); + states[38] = new State(-25); + states[39] = new State(-9); + states[40] = new State(-26,new int[]{-16,41}); + states[41] = new State(new int[]{22,18},new int[]{-13,42,-3,45}); + states[42] = new State(new int[]{19,43,4,-27,10,-27}); + states[43] = new State(new int[]{22,18},new int[]{-3,44}); + states[44] = new State(-29); + states[45] = new State(-28); + states[46] = new State(-10); + states[47] = new State(-3); + + rules[1] = new Rule(-15, new int[]{-1,2}); + rules[2] = new Rule(-1, new int[]{-8}); + rules[3] = new Rule(-14, new int[]{-6}); + rules[4] = new Rule(-14, new int[]{-14,10,-6}); + rules[5] = new Rule(-6, new int[]{-7}); + rules[6] = new Rule(-6, new int[]{-8}); + rules[7] = new Rule(-6, new int[]{-9}); + rules[8] = new Rule(-6, new int[]{-10}); + rules[9] = new Rule(-6, new int[]{-12}); + rules[10] = new Rule(-6, new int[]{-11}); + rules[11] = new Rule(-11, new int[]{}); + rules[12] = new Rule(-3, new int[]{22}); + rules[13] = new Rule(-7, new int[]{-3,6,-2}); + rules[14] = new Rule(-2, new int[]{-2,13,-4}); + rules[15] = new Rule(-2, new int[]{-2,14,-4}); + rules[16] = new Rule(-2, new int[]{-4}); + rules[17] = new Rule(-4, new int[]{-4,15,-5}); + rules[18] = new Rule(-4, new int[]{-4,16,-5}); + rules[19] = new Rule(-4, new int[]{-5}); + rules[20] = new Rule(-5, new int[]{-3}); + rules[21] = new Rule(-5, new int[]{20}); + rules[22] = new Rule(-5, new int[]{17,-2,18}); + rules[23] = new Rule(-8, new int[]{3,-14,4}); + rules[24] = new Rule(-9, new int[]{5,-2,-6}); + rules[25] = new Rule(-10, new int[]{11,17,-2,18}); + rules[26] = new Rule(-16, new int[]{}); + rules[27] = new Rule(-12, new int[]{12,-16,-13}); + rules[28] = new Rule(-13, new int[]{-3}); + rules[29] = new Rule(-13, new int[]{-13,19,-3}); + } + + protected override void Initialize() { + this.InitSpecialTokens((int)Tokens.error, (int)Tokens.EOF); + this.InitStates(states); + this.InitRules(rules); + this.InitNonTerminals(nonTerms); + } + + protected override void DoAction(int action) + { + switch (action) + { + case 2: // progr -> block +{ root = ValueStack[ValueStack.Depth-1].blVal; } + break; + case 3: // stlist -> statement +{ + CurrentSemanticValue.blVal = new BlockNode(ValueStack[ValueStack.Depth-1].stVal); + } + break; + case 4: // stlist -> stlist, SEMICOLON, statement +{ + ValueStack[ValueStack.Depth-3].blVal.Add(ValueStack[ValueStack.Depth-1].stVal); + CurrentSemanticValue.blVal = ValueStack[ValueStack.Depth-3].blVal; + } + break; + case 5: // statement -> assign +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 6: // statement -> block +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].blVal; } + break; + case 7: // statement -> cycle +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 8: // statement -> write +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 9: // statement -> var +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 10: // statement -> empty +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 11: // empty -> /* empty */ +{ CurrentSemanticValue.stVal = new EmptyNode(); } + break; + case 12: // ident -> ID +{ + if (!InDefSect) + if (!SymbolTable.vars.ContainsKey(ValueStack[ValueStack.Depth-1].sVal)) + throw new Exception("("+LocationStack[LocationStack.Depth-1].StartLine+","+LocationStack[LocationStack.Depth-1].StartColumn+"): Переменная "+ValueStack[ValueStack.Depth-1].sVal+" не описана"); + CurrentSemanticValue.eVal = new IdNode(ValueStack[ValueStack.Depth-1].sVal); + } + break; + case 13: // assign -> ident, ASSIGN, expr +{ CurrentSemanticValue.stVal = new AssignNode(ValueStack[ValueStack.Depth-3].eVal as IdNode, ValueStack[ValueStack.Depth-1].eVal); } + break; + case 14: // expr -> expr, PLUS, T +{ CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'+'); } + break; + case 15: // expr -> expr, MINUS, T +{ CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'-'); } + break; + case 16: // expr -> T +{ CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal; } + break; + case 17: // T -> T, MULT, F +{ CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'*'); } + break; + case 18: // T -> T, DIV, F +{ CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'/'); } + break; + case 19: // T -> F +{ CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal; } + break; + case 20: // F -> ident +{ CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal as IdNode; } + break; + case 21: // F -> INUM +{ CurrentSemanticValue.eVal = new IntNumNode(ValueStack[ValueStack.Depth-1].iVal); } + break; + case 22: // F -> LPAREN, expr, RPAREN +{ CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-2].eVal; } + break; + case 23: // block -> BEGIN, stlist, END +{ CurrentSemanticValue.blVal = ValueStack[ValueStack.Depth-2].blVal; } + break; + case 24: // cycle -> CYCLE, expr, statement +{ CurrentSemanticValue.stVal = new CycleNode(ValueStack[ValueStack.Depth-2].eVal,ValueStack[ValueStack.Depth-1].stVal); } + break; + case 25: // write -> WRITE, LPAREN, expr, RPAREN +{ CurrentSemanticValue.stVal = new WriteNode(ValueStack[ValueStack.Depth-2].eVal); } + break; + case 26: // Anon@1 -> /* empty */ +{ InDefSect = true; } + break; + case 27: // var -> VAR, Anon@1, varlist +{ + foreach (var v in (ValueStack[ValueStack.Depth-1].stVal as VarDefNode).vars) + SymbolTable.NewVarDef(v.Name, type.tint); + InDefSect = false; + } + break; + case 28: // varlist -> ident +{ + CurrentSemanticValue.stVal = new VarDefNode(ValueStack[ValueStack.Depth-1].eVal as IdNode); + } + break; + case 29: // varlist -> varlist, COLUMN, ident +{ + (ValueStack[ValueStack.Depth-3].stVal as VarDefNode).Add(ValueStack[ValueStack.Depth-1].eVal as IdNode); + CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-3].stVal; + } + break; + } + } + + protected override string TerminalToString(int terminal) + { + if (aliasses != null && aliasses.ContainsKey(terminal)) + return aliasses[terminal]; + else if (((Tokens)terminal).ToString() != terminal.ToString(CultureInfo.InvariantCulture)) + return ((Tokens)terminal).ToString(); + else + return CharToString((char)terminal); + } + + +} +} diff --git a/Module8/SimpleLanguage3/SimpleYacc.lst b/Module8/SimpleLanguage3/SimpleYacc.lst new file mode 100644 index 0000000..2de6038 --- /dev/null +++ b/Module8/SimpleLanguage3/SimpleYacc.lst @@ -0,0 +1,139 @@ + +// ========================================================================== +// GPPG error listing for yacc source file <SimpleYacc.y> +// ========================================================================== +// Version: 1.3.6 +// Machine: SSM +// DateTime: 19.08.2014 13:28:35 +// UserName: Станислав +// ========================================================================== + + +%{ +// ГќГІГЁ îáúÿâëåГГЁГї äîáà âëÿþòñÿ Гў êëà ññ GPPGParser, ïðåäñòà âëÿþùèé ñîáîé ïà ðñåð, ГЈГҐГåðèðóåìûé ñèñòåìîé gppg + public BlockNode root; // ÊîðГåâîé óçåë Г±ГЁГòà êñè÷åñêîãî äåðåâà + public Parser(AbstractScanner<ValueType, LexLocation> scanner) : base(scanner) { } + private bool InDefSect = false; +%} + +%output = SimpleYacc.cs + +%union { + public double dVal; + public int iVal; + public string sVal; + public Node nVal; + public ExprNode eVal; + public StatementNode stVal; + public BlockNode blVal; + } + +%using System.IO; +%using ProgramTree; + +%namespace SimpleParser + +%start progr + +%token BEGIN END CYCLE ASSIGN ASSIGNPLUS ASSIGNMINUS ASSIGNMULT SEMICOLON WRITE VAR PLUS MINUS MULT DIV LPAREN RPAREN COLUMN +%token <iVal> INUM +%token <dVal> RNUM +%token <sVal> ID + +%type <nVal> varlist +%type <eVal> expr ident T F +%type <stVal> statement assign block cycle write empty var +%type <blVal> stlist block + +%% +// Error: NonTerminal symbol "st" has no productions +// Warning: Terminating st fixes the following size-2 NonTerminal set + // {cycle, st} +// Error: There are 2 non-terminating NonTerminal Symbols + // {cycle, st} +// ------------------------------------------------------------------ + +progr : block { root = $1; } + ; + +stlist : statement + { + $$ = new BlockNode($1); + } + | stlist SEMICOLON statement + { + $1.Add($3); + $$ = $1; + } + ; + +statement: assign { $$ = $1; } + | block { $$ = $1; } + | cycle { $$ = $1; } + | write { $$ = $1; } + | var { $$ = $1; } + | empty { $$ = $1; } + ; + +empty : { $$ = new EmptyNode(); } + ; + +ident : ID + { + if (!InDefSect) + if (!SymbolTable.vars.ContainsKey($1)) + throw new Exception("("+@1.StartLine+","+@1.StartColumn+"): ÏåðåìåГГГ Гї "+$1+" ГГҐ îïèñà ГГ "); + $$ = new IdNode($1); + } + ; + +assign : ident ASSIGN expr { $$ = new AssignNode($1 as IdNode, $3); } + ; + +expr : expr PLUS T { $$ = new BinOpNode($1,$3,'+'); } + | expr MINUS T { $$ = new BinOpNode($1,$3,'-'); } + | T { $$ = $1; } + ; + +T : T MULT F { $$ = new BinOpNode($1,$3,'*'); } + | T DIV F { $$ = new BinOpNode($1,$3,'/'); } + | F { $$ = $1; } + ; + +F : ident { $$ = $1 as IdNode; } + | INUM { $$ = new IntNumNode($1); } + | LPAREN expr RPAREN { $$ = $2; } + ; + +block : BEGIN stlist END { $$ = $2; } + ; + +cycle : CYCLE expr st { $$ = new CycleNode($2,$3); } + ; + +write : WRITE LPAREN expr RPAREN { $$ = new WriteNode($3); } + ; + +var : VAR { InDefSect = true; } varlist + { + foreach (var v in ($3 as VarDefNode).vars) + SymbolTable.NewVarDef(v.Name, type.tint); + InDefSect = false; + } + ; + +varlist : ident + { + $$ = new VarDefNode($1 as IdNode); + } + | varlist COLUMN ident + { + ($1 as VarDefNode).Add($3 as IdNode); + $$ = $1; + } + ; + +%% + +// ========================================================================== + diff --git a/Module8/SimpleLanguage3/SimpleYacc.y b/Module8/SimpleLanguage3/SimpleYacc.y new file mode 100644 index 0000000..20087e0 --- /dev/null +++ b/Module8/SimpleLanguage3/SimpleYacc.y @@ -0,0 +1,119 @@ +%{ +// Эти объявления добавляются в класс GPPGParser, представляющий собой парсер, генерируемый системой gppg + public BlockNode root; // Корневой узел синтаксического дерева + public Parser(AbstractScanner<ValueType, LexLocation> scanner) : base(scanner) { } + private bool InDefSect = false; +%} + +%output = SimpleYacc.cs + +%union { + public double dVal; + public int iVal; + public string sVal; + public Node nVal; + public ExprNode eVal; + public StatementNode stVal; + public BlockNode blVal; + } + +%using System.IO; +%using ProgramTree; + +%namespace SimpleParser + +%start progr + +%token BEGIN END CYCLE ASSIGN ASSIGNPLUS ASSIGNMINUS ASSIGNMULT SEMICOLON WRITE VAR PLUS MINUS MULT DIV LPAREN RPAREN COLUMN +%token <iVal> INUM +%token <dVal> RNUM +%token <sVal> ID + +%type <eVal> expr ident T F +%type <stVal> statement assign block cycle write empty var varlist +%type <blVal> stlist block + +%% + +progr : block { root = $1; } + ; + +stlist : statement + { + $$ = new BlockNode($1); + } + | stlist SEMICOLON statement + { + $1.Add($3); + $$ = $1; + } + ; + +statement: assign { $$ = $1; } + | block { $$ = $1; } + | cycle { $$ = $1; } + | write { $$ = $1; } + | var { $$ = $1; } + | empty { $$ = $1; } + ; + +empty : { $$ = new EmptyNode(); } + ; + +ident : ID + { + if (!InDefSect) + if (!SymbolTable.vars.ContainsKey($1)) + throw new Exception("("+@1.StartLine+","+@1.StartColumn+"): Переменная "+$1+" не описана"); + $$ = new IdNode($1); + } + ; + +assign : ident ASSIGN expr { $$ = new AssignNode($1 as IdNode, $3); } + ; + +expr : expr PLUS T { $$ = new BinOpNode($1,$3,'+'); } + | expr MINUS T { $$ = new BinOpNode($1,$3,'-'); } + | T { $$ = $1; } + ; + +T : T MULT F { $$ = new BinOpNode($1,$3,'*'); } + | T DIV F { $$ = new BinOpNode($1,$3,'/'); } + | F { $$ = $1; } + ; + +F : ident { $$ = $1 as IdNode; } + | INUM { $$ = new IntNumNode($1); } + | LPAREN expr RPAREN { $$ = $2; } + ; + +block : BEGIN stlist END { $$ = $2; } + ; + +cycle : CYCLE expr statement { $$ = new CycleNode($2,$3); } + ; + +write : WRITE LPAREN expr RPAREN { $$ = new WriteNode($3); } + ; + +var : VAR { InDefSect = true; } varlist + { + foreach (var v in ($3 as VarDefNode).vars) + SymbolTable.NewVarDef(v.Name, type.tint); + InDefSect = false; + } + ; + +varlist : ident + { + $$ = new VarDefNode($1 as IdNode); + } + | varlist COLUMN ident + { + ($1 as VarDefNode).Add($3 as IdNode); + $$ = $1; + } + ; + +%% + diff --git a/Module8/SimpleLanguage3/Visitors/AssignCountVisitor.cs b/Module8/SimpleLanguage3/Visitors/AssignCountVisitor.cs new file mode 100644 index 0000000..43d8554 --- /dev/null +++ b/Module8/SimpleLanguage3/Visitors/AssignCountVisitor.cs @@ -0,0 +1,23 @@ +п»їusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProgramTree; + +namespace SimpleLang.Visitors +{ + class AssignCountVisitor : AutoVisitor + { + public int Count = 0; + public override void VisitAssignNode(AssignNode a) + { + Count += 1; + } + public override void VisitWriteNode(WriteNode w) + { + } + public override void VisitVarDefNode(VarDefNode w) + { + } + } +} diff --git a/Module8/SimpleLanguage3/Visitors/AutoVisitor.cs b/Module8/SimpleLanguage3/Visitors/AutoVisitor.cs new file mode 100644 index 0000000..7c92bab --- /dev/null +++ b/Module8/SimpleLanguage3/Visitors/AutoVisitor.cs @@ -0,0 +1,45 @@ +п»їusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProgramTree; + +namespace SimpleLang.Visitors +{ + // базовая логика РѕР±С…РѕРґР° без действий + // Если нужны действия или другая логика РѕР±С…РѕРґР°, то соответствующие методы надо переопределять + // РџСЂРё переопределении методов для задания действий необходимо РЅРµ забывать обходить подузлы + class AutoVisitor: Visitor + { + public override void VisitBinOpNode(BinOpNode binop) + { + binop.Left.Visit(this); + binop.Right.Visit(this); + } + public override void VisitAssignNode(AssignNode a) + { + // для каких-то визиторов РїРѕСЂСЏРґРѕРє может быть обратный - вначале обойти выражение, потом - идентификатор + a.Id.Visit(this); + a.Expr.Visit(this); + } + public override void VisitCycleNode(CycleNode c) + { + c.Expr.Visit(this); + c.Stat.Visit(this); + } + public override void VisitBlockNode(BlockNode bl) + { + foreach (var st in bl.StList) + st.Visit(this); + } + public override void VisitWriteNode(WriteNode w) + { + w.Expr.Visit(this); + } + public override void VisitVarDefNode(VarDefNode w) + { + foreach (var v in w.vars) + v.Visit(this); + } + } +} diff --git a/Module8/SimpleLanguage3/Visitors/GenCodeVisitors/GenCodeCreator.cs b/Module8/SimpleLanguage3/Visitors/GenCodeVisitors/GenCodeCreator.cs new file mode 100644 index 0000000..7353771 --- /dev/null +++ b/Module8/SimpleLanguage3/Visitors/GenCodeVisitors/GenCodeCreator.cs @@ -0,0 +1,104 @@ +п»їusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection.Emit; +using System.Reflection; + +namespace SimpleLang.Visitors +{ + class GenCodeCreator + { + private DynamicMethod dyn; + private ILGenerator gen; + private bool write_commands = true; + private static MethodInfo writeLineInt = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }); + + public List<string> commands = new List<string>(); + + public GenCodeCreator() + { + dyn = new DynamicMethod("My", null, null, typeof(void)); + gen = dyn.GetILGenerator(); + } + + public void Emit(OpCode op) + { + gen.Emit(op); + if (write_commands) + commands.Add(op.ToString()); + } + + public void Emit(OpCode op, int num) + { + gen.Emit(op,num); + if (write_commands) + commands.Add(op.ToString() + " " + num); + } + + public void Emit(OpCode op, LocalBuilder lb) + { + gen.Emit(op, lb); + if (write_commands) + commands.Add(op.ToString() + " var" + lb.LocalIndex); + } + + public void Emit(OpCode op, Label l) + { + gen.Emit(op, l); + if (write_commands) + commands.Add(op.ToString() + " Label" + l.GetHashCode()); + } + + public LocalBuilder DeclareLocal(Type t) + { + var lb = gen.DeclareLocal(t); + if (write_commands) + commands.Add("DeclareLocal " + "var" + lb.LocalIndex + ": " + t); + return lb; + } + + public Label DefineLabel() + { + var l = gen.DefineLabel(); + if (write_commands) + commands.Add("DefineLabel" + " Label" + l.GetHashCode()); + + return l; + } + + public void MarkLabel(Label l) + { + gen.MarkLabel(l); + if (write_commands) + commands.Add("MarkLabel" + " Label" + l.GetHashCode()); + } + + public void EmitWriteLine() + { + gen.Emit(OpCodes.Call, writeLineInt); + if (write_commands) + commands.Add("WriteLine"); + } + + public void EndProgram() + { + gen.Emit(OpCodes.Ret); + } + + public void RunProgram() + { + dyn.Invoke(null, null); + } + + public void WriteCommandsOn() + { + write_commands = true; + } + + public void WriteCommandsOff() + { + write_commands = false; + } + } +} diff --git a/Module8/SimpleLanguage3/Visitors/GenCodeVisitors/GenCodeVisitor.cs b/Module8/SimpleLanguage3/Visitors/GenCodeVisitors/GenCodeVisitor.cs new file mode 100644 index 0000000..58959fa --- /dev/null +++ b/Module8/SimpleLanguage3/Visitors/GenCodeVisitors/GenCodeVisitor.cs @@ -0,0 +1,113 @@ +п»їusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProgramTree; +using System.Reflection.Emit; + +namespace SimpleLang.Visitors +{ + class GenCodeVisitor: Visitor + { + private Dictionary<string, LocalBuilder> vars = new Dictionary<string, LocalBuilder>(); + private GenCodeCreator genc; + + public GenCodeVisitor() + { + genc = new GenCodeCreator(); + } + public override void VisitIdNode(IdNode id) + { + // Ртот Visit РЅРµ вызывается если переменная стоит слева РѕС‚ оператора присваивания ! + // Рў.Рµ. РѕРЅ вызывается только если id находится РІ выражении, Р° значит, РјС‹ просто кладем его значение РЅР° стек! + genc.Emit(OpCodes.Ldloc, vars[id.Name]); + } + public override void VisitIntNumNode(IntNumNode num) + { + genc.Emit(OpCodes.Ldc_I4, num.Num); + } + public override void VisitBinOpNode(BinOpNode binop) + { + binop.Left.Visit(this); + binop.Right.Visit(this); + switch (binop.Op) + { + case '+': + genc.Emit(OpCodes.Add); + break; + case '-': + genc.Emit(OpCodes.Sub); + break; + case '*': + genc.Emit(OpCodes.Mul); + break; + case '/': + genc.Emit(OpCodes.Div); + break; + } + } + public override void VisitAssignNode(AssignNode a) + { + a.Expr.Visit(this); + genc.Emit(OpCodes.Stloc, vars[a.Id.Name]); + } + public override void VisitCycleNode(CycleNode c) + { + var i = genc.DeclareLocal(typeof(int)); // переменная цикла cycle + c.Expr.Visit(this); // сгенерировать команды, связанные СЃ вычислением количества итераций цикла + genc.Emit(OpCodes.Stloc, i); // i := РєРІРѕ итераций + + Label startLoop = genc.DefineLabel(); + Label endLoop = genc.DefineLabel(); + + genc.MarkLabel(startLoop); + + genc.Emit(OpCodes.Ldloc, i); + genc.Emit(OpCodes.Ldc_I4_0); + genc.Emit(OpCodes.Ble, endLoop); // if i<=0 then goto endLoop + + c.Stat.Visit(this); // выполнить тело цикла + + genc.Emit(OpCodes.Ldloc, i); // положить i РЅР° стек + genc.Emit(OpCodes.Ldc_I4_1); // положить 1 РЅР° стек + genc.Emit(OpCodes.Sub); + genc.Emit(OpCodes.Stloc, i); // i := i - 1; + + genc.Emit(OpCodes.Br, startLoop); + + genc.MarkLabel(endLoop); + } + public override void VisitBlockNode(BlockNode bl) + { + foreach (var st in bl.StList) + st.Visit(this); + } + public override void VisitWriteNode(WriteNode w) + { + w.Expr.Visit(this); + genc.EmitWriteLine(); + } + + public override void VisitVarDefNode(VarDefNode w) + { + foreach (var v in w.vars) + vars[v.Name] = genc.DeclareLocal(typeof(int)); + } + + public void EndProgram() + { + genc.EndProgram(); + } + + public void RunProgram() + { + genc.RunProgram(); + } + + public void PrintCommands() + { + foreach (var s in genc.commands) + Console.WriteLine(s); + } + } +} diff --git a/Module8/SimpleLanguage3/Visitors/PrettyPrintVisitor.cs b/Module8/SimpleLanguage3/Visitors/PrettyPrintVisitor.cs new file mode 100644 index 0000000..87892b1 --- /dev/null +++ b/Module8/SimpleLanguage3/Visitors/PrettyPrintVisitor.cs @@ -0,0 +1,88 @@ +п»їusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProgramTree; + +namespace SimpleLang.Visitors +{ + class PrettyPrintVisitor: Visitor + { + public string Text = ""; + private int Indent = 0; + + private string IndentStr() + { + return new string(' ', Indent); + } + private void IndentPlus() + { + Indent += 2; + } + private void IndentMinus() + { + Indent -= 2; + } + public override void VisitIdNode(IdNode id) + { + Text += id.Name; + } + public override void VisitIntNumNode(IntNumNode num) + { + Text += num.Num.ToString(); + } + public override void VisitBinOpNode(BinOpNode binop) + { + Text += "("; + binop.Left.Visit(this); + Text += " " + binop.Op + " "; + binop.Right.Visit(this); + Text += ")"; + } + public override void VisitAssignNode(AssignNode a) + { + Text += IndentStr(); + a.Id.Visit(this); + Text += " := "; + a.Expr.Visit(this); + } + public override void VisitCycleNode(CycleNode c) + { + Text += IndentStr() + "cycle "; + c.Expr.Visit(this); + Text += Environment.NewLine; + c.Stat.Visit(this); + } + public override void VisitBlockNode(BlockNode bl) + { + Text += IndentStr() + "begin" + Environment.NewLine; + IndentPlus(); + + var Count = bl.StList.Count; + + if (Count>0) + bl.StList[0].Visit(this); + for (var i = 1; i < Count; i++) + { + Text += ';'; + if (!(bl.StList[i] is EmptyNode)) + Text += Environment.NewLine; + bl.StList[i].Visit(this); + } + IndentMinus(); + Text += Environment.NewLine + IndentStr() + "end"; + } + public override void VisitWriteNode(WriteNode w) + { + Text += IndentStr() + "write("; + w.Expr.Visit(this); + Text += ")"; + } + public override void VisitVarDefNode(VarDefNode w) + { + Text += IndentStr() + "var " + w.vars[0].Name; + for (int i = 1; i < w.vars.Count; i++) + Text += ',' + w.vars[i].Name; + } + } +} diff --git a/Module8/SimpleLanguage3/Visitors/Visitor.cs b/Module8/SimpleLanguage3/Visitors/Visitor.cs new file mode 100644 index 0000000..b9dcae0 --- /dev/null +++ b/Module8/SimpleLanguage3/Visitors/Visitor.cs @@ -0,0 +1,21 @@ +п»їusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProgramTree; + +namespace SimpleLang.Visitors +{ + public abstract class Visitor + { + public virtual void VisitIdNode(IdNode id) { } + public virtual void VisitIntNumNode(IntNumNode num) { } + public virtual void VisitBinOpNode(BinOpNode binop) { } + public virtual void VisitAssignNode(AssignNode a) { } + public virtual void VisitCycleNode(CycleNode c) { } + public virtual void VisitBlockNode(BlockNode bl) { } + public virtual void VisitWriteNode(WriteNode w) { } + public virtual void VisitVarDefNode(VarDefNode w) { } + public virtual void VisitEmptyNode(EmptyNode w) { } + } +} diff --git a/Module8/SimpleLanguage3/a.txt b/Module8/SimpleLanguage3/a.txt new file mode 100644 index 0000000..14eeab4 --- /dev/null +++ b/Module8/SimpleLanguage3/a.txt @@ -0,0 +1,11 @@ +begin + var a,b,d; + b := 2; + a := 3; + a := a * 4 + b;;; + cycle 3 + begin + a := a + 1; + write(a) + end +end diff --git a/Module8/SimpleLanguage3/generateParserScanner.bat b/Module8/SimpleLanguage3/generateParserScanner.bat new file mode 100644 index 0000000..7ca5476 --- /dev/null +++ b/Module8/SimpleLanguage3/generateParserScanner.bat @@ -0,0 +1,3 @@ +cls +gplex.exe /unicode SimpleLex.lex +gppg.exe /no-lines /gplex SimpleYacc.y -- GitLab