From 6582c6b8aa79d198f18bc72323b9809e9fbd715b Mon Sep 17 00:00:00 2001 From: Fomenko Dmitrii <dfomenko@corp.finam.ru> Date: Sun, 29 Jan 2023 22:08:32 +0300 Subject: [PATCH] push labs --- Module1/Lexer.cs | 473 +++++++++-------- Module1/Lexer.csproj | 15 + Module1/packages.config | 6 + Module2/SimpleLangLexer/SimpleLexer.cs | 164 +++++- Module2/SimpleLangLexer/SimpleLexer.csproj | 17 + Module2/SimpleLangLexer/packages.config | 6 + .../SimpleLexerDemo/SimpleLexerDemo.csproj | 15 + Module2/SimpleLexerDemo/packages.config | 6 + Module3/GeneratedLexer.csproj | 15 + Module3/Gplex.exe | Bin 0 -> 240640 bytes Module3/LexerAddon.cs | 34 +- Module3/SimpleLex.cs | 493 +++++++++++------- Module3/SimpleLex.lex | 47 ++ Module3/SimpleLex.lst | 141 +++++ Module3/a.txt | 4 +- Module3/mymain.cs | 24 +- Module3/packages.config | 6 + .../RecursiveDescentParser.csproj | 17 + Module4/SimpleLangParser/SimpleLangParser.cs | 138 ++++- Module4/SimpleLangParser/packages.config | 6 + .../RecursiveDescentParserDemo.csproj | 15 + Module4/SimpleLangParserTest/packages.config | 6 + Module5/GeneratedParser.csproj | 15 + Module5/SimpleLex.cs | 250 +++++---- Module5/SimpleLex.lex | 22 + Module5/SimpleYacc.cs | 179 ++++--- Module5/SimpleYacc.lst | 43 +- Module5/SimpleYacc.y | 55 +- Module5/packages.config | 6 + Module6/ParserAST.csproj | 14 + Module6/ProgramTree.cs | 92 ++++ Module6/SimpleLex.cs | 247 +++++---- Module6/SimpleLex.lex | 21 + Module6/SimpleYacc.cs | 262 +++++++--- Module6/SimpleYacc.y | 54 +- Module6/generateParserScanner.bat | 1 + Module6/packages.config | 3 + Module7/ParserVistors.csproj | 15 + Module7/ProgramTree.cs | 28 + Module7/SimpleLex.cs | 169 +++--- Module7/SimpleLex.lex | 4 + Module7/SimpleYacc.cs | 242 ++++----- Module7/SimpleYacc.y | 10 +- Module7/Visitors/AutoVisitor.cs | 9 + Module7/Visitors/ChangeVarIdVisitor.cs | 9 +- Module7/Visitors/CommonlyUsedVarVisitor.cs | 21 +- Module7/Visitors/CountCyclesOpVisitor.cs | 30 +- Module7/Visitors/ExprComplexityVisitor.cs | 45 +- Module7/Visitors/MaxIfCycleNestVisitor.cs | 23 + Module7/Visitors/MaxNestCyclesVisitor.cs | 13 + Module7/Visitors/PrettyPrintVisitor.cs | 13 + Module7/Visitors/Visitor.cs | 1 + Module7/packages.config | 6 + Module8/ParserGenerator.csproj | 15 + Module8/ProgramTree.cs | 31 ++ Module8/SimpleLex.cs | 232 +++++---- Module8/SimpleLex.lex | 10 + Module8/SimpleYacc.cs | 285 +++++----- Module8/SimpleYacc.y | 21 +- Module8/Visitors/AutoVisitor.cs | 13 + .../GenCodeVisitors/GenCodeVisitor.cs | 53 ++ Module8/Visitors/Visitor.cs | 3 + Module8/packages.config | 6 + NunitReportParser/NunitReport.csproj | 14 + NunitReportParser/packages.config | 3 + TestASTParser/Tests.cs | 46 +- TestCodeGenerator/Tests.cs | 2 +- TestDescentParser/Tests.cs | 6 +- TestGeneratedLexer/Tests.cs | 12 +- TestLexer/Tests.cs | 25 +- TestSimpleLexer/Tests.cs | 10 +- TestVisitors/Tests.cs | 35 +- 72 files changed, 3100 insertions(+), 1272 deletions(-) create mode 100644 Module1/packages.config create mode 100644 Module2/SimpleLangLexer/packages.config create mode 100644 Module2/SimpleLexerDemo/packages.config create mode 100644 Module3/Gplex.exe create mode 100644 Module3/SimpleLex.lst create mode 100644 Module3/packages.config create mode 100644 Module4/SimpleLangParser/packages.config create mode 100644 Module4/SimpleLangParserTest/packages.config create mode 100644 Module5/packages.config create mode 100644 Module7/packages.config create mode 100644 Module8/packages.config diff --git a/Module1/Lexer.cs b/Module1/Lexer.cs index af2b9ee..cb01e37 100644 --- a/Module1/Lexer.cs +++ b/Module1/Lexer.cs @@ -1,7 +1,8 @@ using System; +using System.Text; using System.Collections.Generic; +using System.Globalization; using System.Linq; -using System.Text; namespace Lexer { @@ -42,7 +43,7 @@ namespace Lexer protected void NextCh() { this.currentCharValue = this.inputReader.Read(); - this.currentCh = (char)currentCharValue; + this.currentCh = (char) currentCharValue; this.position += 1; } @@ -50,6 +51,11 @@ namespace Lexer { return true; } + + protected int currentDigit() + { + return currentCharValue - '0'; + } } public class IntLexer : Lexer @@ -66,19 +72,17 @@ namespace Lexer public override bool Parse() { - int sign = 1; + bool isNeg = false; NextCh(); if (currentCh == '+' || currentCh == '-') { - if (currentCh == '-') - sign = -1; - + if (currentCh == '-') isNeg = true; NextCh(); } - + if (char.IsDigit(currentCh)) { - parseResult = currentCh - '0'; + parseResult = currentDigit(); NextCh(); } else @@ -88,65 +92,67 @@ namespace Lexer while (char.IsDigit(currentCh)) { - parseResult = parseResult * 10 + currentCh - '0'; + parseResult = parseResult * 10 + currentDigit(); NextCh(); } - parseResult *= sign; + // если есть еще что прочитать => не число if (currentCharValue != -1) { Error(); } + if (isNeg) + { + parseResult = -parseResult; + } + return true; } } - + public class IdentLexer : Lexer { private string parseResult; protected StringBuilder builder; - + public string ParseResult { get { return parseResult; } } - + public IdentLexer(string input) : base(input) { builder = new StringBuilder(); } - bool checkChar(char ch) - { - return char.IsDigit(ch) || - (ch >= 'A' && ch <= 'Z') || - (ch >= 'a' && ch <= 'z') || - ch == '_'; - } public override bool Parse() { NextCh(); - - if (!checkChar(currentCh)) + if (currentCharValue == -1) + { Error(); + } - while (checkChar(currentCh)) + while (currentCharValue != -1) { - parseResult += currentCh; - NextCh(); + if (char.IsLetterOrDigit(currentCh) || currentCh == '_') + { + builder.Append(currentCh); + NextCh(); + } + else + { + Error(); + } } - if (currentCharValue != -1) - Error(); + parseResult = builder.ToString(); return true; - - //throw new NotImplementedException(); } - } public class IntNoZeroLexer : IntLexer @@ -158,20 +164,17 @@ namespace Lexer public override bool Parse() { - - int sign = 1; + bool isNeg = false; NextCh(); if (currentCh == '+' || currentCh == '-') { - if (currentCh == '-') - sign = -1; - + if (currentCh == '-') isNeg = true; NextCh(); } if (char.IsDigit(currentCh) && currentCh != '0') { - parseResult = currentCh - '0'; + parseResult = currentDigit(); NextCh(); } else @@ -181,19 +184,22 @@ namespace Lexer while (char.IsDigit(currentCh)) { - parseResult = parseResult * 10 + currentCh - '0'; + parseResult = parseResult * 10 + currentDigit(); NextCh(); } - parseResult *= sign; + // если есть еще что прочитать => не число if (currentCharValue != -1) { Error(); } - return true; + if (isNeg) + { + parseResult = -parseResult; + } - throw new NotImplementedException(); + return true; } } @@ -202,6 +208,8 @@ namespace Lexer protected StringBuilder builder; protected string parseResult; + private bool passChar = true; + public string ParseResult { get { return parseResult; } @@ -212,21 +220,44 @@ namespace Lexer { builder = new StringBuilder(); } - public override bool Parse() + + private void parse() { - bool isDigit = false; + if (passChar) + { + if (char.IsLetter(currentCh)) + { + builder.Append(currentCh); + } + else + { + Error(); + } + } + else + { + if (char.IsDigit(currentCh)) + { + builder.Append(currentCh); + } + else + { + Error(); + } + } + passChar = !passChar; + } - NextCh(); + public override bool Parse() + { + NextCh(); while (currentCharValue != -1) { - if (char.IsDigit(currentCh) ^ isDigit || currentCh == ' ') - Error(); - - isDigit = !isDigit; + parse(); NextCh(); } - + parseResult = builder.ToString(); return true; } @@ -236,6 +267,11 @@ namespace Lexer { protected List<char> parseResult; + private bool passChar = true; // true for letter, false for sign + + private List<char> delimeters = new List<char> { ',', ';' }; + + public List<char> ParseResult { get { return parseResult; } @@ -247,28 +283,44 @@ namespace Lexer parseResult = new List<char>(); } - public override bool Parse() + private void parse() { - bool isChar = false; - - NextCh(); - while (currentCharValue != -1) + if (passChar) { - if ((currentCh == ',' || currentCh == ';') ^ isChar - || char.IsDigit(currentCh)) + if (char.IsLetter(currentCh)) + { + parseResult.Add(currentCh); + } + else + { + Error(); + } + } + else + { + if (!delimeters.Contains(currentCh)) + { Error(); + } + } + passChar = !passChar; + } - if (!(currentCh == ',' || currentCh == ';') && !isChar) - parseResult.Add(currentCh); - isChar = !isChar; + public override bool Parse() + { + NextCh(); + while (currentCharValue != -1) + { + parse(); NextCh(); } - - if (!isChar) + if (passChar) + { Error(); - + } return true; + } } @@ -289,38 +341,34 @@ namespace Lexer public override bool Parse() { - bool flag = true; - NextCh(); - if (currentCh == ' ' || !char.IsDigit(currentCh)) + if (!char.IsDigit(currentCh)) { Error(); } - - parseResult.Add(currentCh - '0'); - - NextCh(); - while (currentCharValue != -1) + while (true) { - if (currentCh == ' ') - { - flag = false; - } - else + if (char.IsDigit(currentCh)) { - if (!flag) + parseResult.Add(currentCharValue - '0'); + NextCh(); + if (char.IsDigit(currentCh)) + { + Error(); + } + if (currentCharValue == -1) { - flag = true; - parseResult.Add(currentCh - '0'); + return true; } - else Error(); + } + // скипаем пробелы + // если попалась вторая цифра(буква) => ошибка + if (!char.IsWhiteSpace(currentCh)) + { + Error(); } NextCh(); } - if (!flag) - Error(); - - return true; } } @@ -333,7 +381,7 @@ namespace Lexer { get { return parseResult; } } - + public LetterDigitGroupLexer(string input) : base(input) { @@ -342,58 +390,44 @@ namespace Lexer public override bool Parse() { - bool lastIsDigit = true; - bool isDigit; - int countCurrentChar = 0; - + int lettersInRow = 0; + int digitsInRow = 0; NextCh(); - if (currentCh == ' ' || currentCh == '\uffff')//'\uffff' - non-char + if (currentCharValue == -1 || !char.IsLetter(currentCh)) { Error(); } - else + + builder.Append(currentCh); + lettersInRow += 1; + + NextCh(); + while (currentCharValue != -1) { - if (char.IsDigit(currentCh) || currentCh == '_') + if (lettersInRow > 2 || digitsInRow > 2) { Error(); } - else + if (char.IsDigit(currentCh)) { - isDigit = false; - lastIsDigit = isDigit; + builder.Append(currentCh); + digitsInRow += 1; + lettersInRow = 0; } - builder.Append(currentCh); - countCurrentChar++; - } - NextCh(); - while (currentCharValue != -1) - { - if (currentCh == ' ' || currentCh == '_') + else if (char.IsLetter(currentCh)) { - Error(); + builder.Append(currentCh); + lettersInRow += 1; + digitsInRow = 0; } else { - isDigit = char.IsDigit(currentCh); - - if (lastIsDigit != isDigit) - { - countCurrentChar = 0; - lastIsDigit = isDigit; - } - - builder.Append(currentCh); - countCurrentChar++; - - if (countCurrentChar == 3) - Error(); - - NextCh(); + Error(); } + NextCh(); } parseResult = builder.ToString(); - return true; } @@ -407,6 +441,7 @@ namespace Lexer public double ParseResult { get { return parseResult; } + } public DoubleLexer(string input) @@ -417,36 +452,47 @@ namespace Lexer public override bool Parse() { - bool havePoint = false; NextCh(); - if (char.IsDigit(currentCh)) + if (!char.IsDigit(currentCh)) { - builder.Append(currentCh); + Error(); } - else + while (char.IsDigit(currentCh)) { - Error(); + parseResult = parseResult * 10 + currentDigit(); + NextCh(); } - NextCh(); - while (currentCharValue != -1) + + if (currentCharValue == -1) { - if (currentCh == '.') - { - if (havePoint == true) - Error(); + return true; + } - havePoint = true; - } - builder.Append(currentCh); - NextCh(); + if (currentCh != '.') + { + Error(); } - if (builder.ToString().Last() == '.') + NextCh(); + if (!char.IsDigit(currentCh)) + { Error(); + } - parseResult = double.Parse(builder.ToString()); + double power = 1; + while (char.IsDigit(currentCh)) + { + power /= 10; + parseResult += currentDigit() * power; + NextCh(); + } + if (currentCharValue != -1) + { + Error(); + } return true; + } } @@ -470,40 +516,34 @@ namespace Lexer public override bool Parse() { - int count = 0; - NextCh(); - - if (currentCh == ' ') - Error(); - - if (currentCh == '\'') + // первая кавычка + if (currentCh != '\'') { - count++; + Error(); } - builder.Append(currentCh); NextCh(); - - while (currentCharValue != -1) + while (currentCh != '\'' && currentCharValue != -1) { - if (currentCh == ' ' && count % 2 == 0) - Error(); - - if (currentCh == '\'') - { - count++; - } builder.Append(currentCh); NextCh(); } - if (count % 2 == 1) + // вторая кавычка + if (currentCh != '\'') + { Error(); + } + NextCh(); + if (currentCharValue != -1) + { + Error(); + } parseResult = builder.ToString(); - return true; + } } @@ -526,68 +566,54 @@ namespace Lexer public override bool Parse() { - int flag_before = 0;//0 - не было, 1 - было, 2 - завершено - bool flag_before_final = false;//открывающая /* - - int flag_after = 0;//закрывающая */ - bool flag_after_final = false; - NextCh(); - if (currentCh == ' ') + if (currentCh == '/') + { + NextCh(); + } + else + { Error(); - else if (currentCh == '/') + } + + if (currentCh == '*') { - flag_before = 1; + NextCh(); } - builder.Append(currentCh); - NextCh(); + else + { + Error(); + } + // конец начала комментария while (currentCharValue != -1) { - if (flag_after_final == true)//Если зашли в цикл после комментариев - Error(); - - if (currentCh == '/')//Для открывающей - { - flag_before = 1; - } - - if (currentCh == '*' && flag_before_final == true)//Для закрывающей - { - flag_after = 1; - } - - if (currentCh == '*')//Для открывающей + // проверка на конец комментария + if (currentCh == '*') { - if (flag_before == 1) + NextCh(); + if (currentCh == '/') { - flag_before = 2; - flag_before_final = true; + NextCh(); + if (currentCharValue == -1) + { + return true; + } + else + { + Error(); + } } - else flag_before = 0; - } - - if (currentCh == '/')//Для закрывающей - { - if (flag_after == 1) + else { - flag_after = 2; - flag_after_final = true; + continue; } - else flag_after = 0; } - - - builder.Append(currentCh); NextCh(); } + Error(); + return false; - if (!flag_after_final) - Error(); - - parseResult = builder.ToString(); - - return true; } } @@ -611,49 +637,34 @@ namespace Lexer public override bool Parse() { - string temp = ""; - bool dot_flag = true;//0 - всё хорошо. 1 - id1.id2. - + int lastSymbol = 0; NextCh(); - if (currentCharValue == -1) - { - Error(); - } - while (currentCharValue != -1) { - dot_flag = false; - if (currentCh == '$' || currentCh == ' ' || currentCh == ',') + // если первый символ число - ошибка + if (char.IsDigit(currentCh)) { Error(); } - if (currentCh == '.') + // читаем до точки, потом делаем IdentLexer + while (currentCh != '.' + && currentCharValue != -1) { - temp = builder.ToString(); - if (temp.Length == 0 || char.IsDigit(temp[0])) - Error(); - - parseResult.Add(temp); - builder.Clear(); - dot_flag = true; + builder.Append(currentCh); + NextCh(); } - else - builder.Append(currentCh.ToString()); - + lastSymbol = currentCharValue; + IdentLexer id = new IdentLexer(builder.ToString()); + id.Parse(); + parseResult.Add(id.ParseResult); + builder.Clear(); NextCh(); } - - if (dot_flag == true || currentCharValue != -1) - Error(); - - temp = builder.ToString(); - - if (char.IsDigit(temp[0])) + if (lastSymbol != -1) + { Error(); - - parseResult.Add(temp); - + } return true; } } diff --git a/Module1/Lexer.csproj b/Module1/Lexer.csproj index 6bfb931..7592ce6 100644 --- a/Module1/Lexer.csproj +++ b/Module1/Lexer.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> @@ -13,6 +15,8 @@ <FileAlignment>512</FileAlignment> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <TargetFrameworkProfile /> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> @@ -42,6 +46,9 @@ <Reference Include="Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <HintPath>C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.dll</HintPath> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> @@ -55,8 +62,16 @@ </ItemGroup> <ItemGroup> <None Include="App.config" /> + <None Include="packages.config" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> <!-- 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"> diff --git a/Module1/packages.config b/Module1/packages.config new file mode 100644 index 0000000..e68db37 --- /dev/null +++ b/Module1/packages.config @@ -0,0 +1,6 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> +</packages> \ No newline at end of file diff --git a/Module2/SimpleLangLexer/SimpleLexer.cs b/Module2/SimpleLangLexer/SimpleLexer.cs index 7bd0af4..87e0cd8 100644 --- a/Module2/SimpleLangLexer/SimpleLexer.cs +++ b/Module2/SimpleLangLexer/SimpleLexer.cs @@ -100,6 +100,19 @@ namespace SimpleLexer keywordsMap["begin"] = Tok.BEGIN; keywordsMap["end"] = Tok.END; keywordsMap["cycle"] = Tok.CYCLE; + keywordsMap["div"] = Tok.DIV; + keywordsMap["mod"] = Tok.MOD; + keywordsMap["and"] = Tok.AND; + keywordsMap["or"] = Tok.OR; + keywordsMap["not"] = Tok.NOT; + keywordsMap["while"] = Tok.WHILE; + keywordsMap["for"] = Tok.FOR; + keywordsMap["if"] = Tok.IF; + keywordsMap["to"] = Tok.TO; + keywordsMap["do"] = Tok.DO; + keywordsMap["then"] = Tok.THEN; + keywordsMap["else"] = Tok.ELSE; + } public string FinishCurrentLine() @@ -166,12 +179,16 @@ namespace SimpleLexer else if (currentCh == ':') { NextCh(); - if (currentCh != '=') + if (currentCh == '=') { - LexError("= was expected"); + LexKind = Tok.ASSIGN; + NextCh(); } - NextCh(); - LexKind = Tok.ASSIGN; + else + { + LexKind = Tok.COLON; + } + } else if (char.IsLetter(currentCh)) { @@ -201,6 +218,145 @@ namespace SimpleLexer { LexKind = Tok.EOF; } + else if (currentCh == ',') + { + LexKind = Tok.COMMA; + NextCh(); + } + else if (currentCh == '+') + { + NextCh(); + if (currentCh == '=') + { + LexKind = Tok.PLUSASSIGN; + NextCh(); + } + else + { + LexKind = Tok.PLUS; + } + + } + else if (currentCh == '-') + { + NextCh(); + if (currentCh == '=') + { + LexKind = Tok.MINUSASSIGN; + NextCh(); + } + else + { + LexKind = Tok.MINUS; + } + } + else if (currentCh == '*') + { + NextCh(); + if (currentCh == '=') + { + LexKind = Tok.MULTASSIGN; + NextCh(); + } + else + { + LexKind = Tok.MULT; + } + } + else if (currentCh == '/') + { + NextCh(); + if (currentCh == '=') + { + LexKind = Tok.DIVASSIGN; + NextCh(); + } + else if (currentCh == '/') + { + NextCh(); + while ((int)currentCh != 0 && (currentCh != '\n')) + { + NextCh(); + } + if (currentCh == '\n') + { + NextCh(); + NextLexem(); + } + else + { + LexKind = Tok.EOF; + } + } + else + { + LexKind = Tok.DIVISION; + } + } + else if (currentCh == '=') + { + LexKind = Tok.EQ; + NextCh(); + } + else if (currentCh == '>') + { + NextCh(); + if (currentCh == '=') + { + LexKind = Tok.GEQ; + NextCh(); + } + else + { + LexKind = Tok.GT; + } + } + else if (currentCh == '<') + { + NextCh(); + if (currentCh == '=') + { + LexKind = Tok.LEQ; + NextCh(); + } + else if (currentCh == '>') + { + LexKind = Tok.NEQ; + NextCh(); + } + else + { + LexKind = Tok.LT; + } + } + else if (currentCh == '{') + { + NextCh(); + while ((int)currentCh != 0 && (currentCh != '}')) + { + NextCh(); + } + if (currentCh == '}') + { + NextCh(); + NextLexem(); + } + else + { + LexError("No closing bracket"); + } + } + else if (currentCh == '(') + { + LexKind = Tok.LEFT_BRACKET; + NextCh(); + } + else if (currentCh == ')') + { + LexKind = Tok.RIGHT_BRACKET; + NextCh(); + } + else { LexError("Incorrect symbol " + currentCh); diff --git a/Module2/SimpleLangLexer/SimpleLexer.csproj b/Module2/SimpleLangLexer/SimpleLexer.csproj index 10cf9bd..97c1aa2 100644 --- a/Module2/SimpleLangLexer/SimpleLexer.csproj +++ b/Module2/SimpleLangLexer/SimpleLexer.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\..\packages\NUnit.3.12.0\build\NUnit.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> @@ -12,6 +14,8 @@ <TargetFrameworkVersion>v4.8</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <TargetFrameworkProfile /> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> @@ -41,6 +45,9 @@ <Reference Include="Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <HintPath>C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.dll</HintPath> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> @@ -52,7 +59,17 @@ <Compile Include="SimpleLexer.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> <!-- 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"> diff --git a/Module2/SimpleLangLexer/packages.config b/Module2/SimpleLangLexer/packages.config new file mode 100644 index 0000000..e68db37 --- /dev/null +++ b/Module2/SimpleLangLexer/packages.config @@ -0,0 +1,6 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> +</packages> \ No newline at end of file diff --git a/Module2/SimpleLexerDemo/SimpleLexerDemo.csproj b/Module2/SimpleLexerDemo/SimpleLexerDemo.csproj index c1cae76..e4201b4 100644 --- a/Module2/SimpleLexerDemo/SimpleLexerDemo.csproj +++ b/Module2/SimpleLexerDemo/SimpleLexerDemo.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\..\packages\NUnit.3.12.0\build\NUnit.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> @@ -12,6 +14,8 @@ <TargetFrameworkVersion>v4.8</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <TargetFrameworkProfile /> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> @@ -38,6 +42,9 @@ <Reference Include="Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <HintPath>C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.dll</HintPath> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> @@ -57,8 +64,16 @@ </ItemGroup> <ItemGroup> <None Include="app.config" /> + <None Include="packages.config" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> <!-- 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"> diff --git a/Module2/SimpleLexerDemo/packages.config b/Module2/SimpleLexerDemo/packages.config new file mode 100644 index 0000000..e68db37 --- /dev/null +++ b/Module2/SimpleLexerDemo/packages.config @@ -0,0 +1,6 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> +</packages> \ No newline at end of file diff --git a/Module3/GeneratedLexer.csproj b/Module3/GeneratedLexer.csproj index d424603..33a17c2 100644 --- a/Module3/GeneratedLexer.csproj +++ b/Module3/GeneratedLexer.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0"> + <Import Project="..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> @@ -34,6 +36,8 @@ <BootstrapperEnabled>true</BootstrapperEnabled> <LangVersion>5</LangVersion> <TargetFrameworkProfile /> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> @@ -54,6 +58,9 @@ <Reference Include="Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <HintPath>C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.dll</HintPath> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Data" /> <Reference Include="System.Xml" /> @@ -94,10 +101,18 @@ </ItemGroup> <ItemGroup> <None Include="app.config" /> + <None Include="packages.config" /> <None Include="SimpleLex.lex" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" /> <ProjectExtensions> <VisualStudio AllowExistingFolder="true" /> </ProjectExtensions> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> </Project> \ No newline at end of file diff --git a/Module3/Gplex.exe b/Module3/Gplex.exe new file mode 100644 index 0000000000000000000000000000000000000000..51a522e221f5ca52cc934933e08745f1653a98b5 GIT binary patch literal 240640 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 literal 0 HcmV?d00001 diff --git a/Module3/LexerAddon.cs b/Module3/LexerAddon.cs index c246779..da6df4c 100644 --- a/Module3/LexerAddon.cs +++ b/Module3/LexerAddon.cs @@ -19,7 +19,10 @@ namespace GeneratedLexer public int sumInt = 0; public double sumDouble = 0.0; public List<string> idsInComment = new List<string>(); - + + public string apostrophe = ""; + + public LexerAddon(string programText) { @@ -37,6 +40,8 @@ namespace GeneratedLexer public void Lex() { + int sum_id_len = 0; //sum длина идентификатора + // Чтобы вещественные числа распознавались и отображались в формате 3.14 (а не 3,14 как в русской Culture) System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); @@ -46,8 +51,35 @@ namespace GeneratedLexer if (tok == (int)Tok.EOF) { + avgIdLength = idCount != 0 ? (double)sum_id_len / idCount : 0; break; } + else if (tok == (int)Tok.ID) + { + idCount++; + int length = myScanner.yytext.Length; + sum_id_len += length; + minIdLength = length < minIdLength ? length : minIdLength; + maxIdLength = length > maxIdLength ? length : maxIdLength; + } + else if (tok == (int)Tok.INUM) + { + sumInt += myScanner.LexValueInt; + } + else if (tok == (int)Tok.RNUM) + { + sumDouble += myScanner.LexValueDouble; + } + else if (tok == (int)Tok.STRINGAP) + { + apostrophe = myScanner.yytext; + } + else if (tok == (int)Tok.LONGCOMMENT) + { + idsInComment.Add(myScanner.yytext); + } + + } while (true); } } diff --git a/Module3/SimpleLex.cs b/Module3/SimpleLex.cs index d8f9df8..169af75 100644 --- a/Module3/SimpleLex.cs +++ b/Module3/SimpleLex.cs @@ -1,14 +1,10 @@ // // This CSharp output file generated by Gardens Point LEX -// Gardens Point LEX (GPLEX) is Copyright (c) John Gough, QUT 2006-2014. -// Output produced by GPLEX is the property of the user. -// See accompanying file GPLEXcopyright.rtf. -// -// GPLEX Version: 1.2.2 -// Machine: MAINHOMEPC2 -// DateTime: 30.09.2018 17:57:38 -// UserName: someone -// GPLEX input file <SimpleLex.lex - 30.09.2018 17:56:56> +// Version: 1.1.3.301 +// Machine: WIN-51KGPO1PTR9 +// DateTime: 27.11.2022 17:31:31 +// UserName: ????????????? +// GPLEX input file <SimpleLex.lex> // GPLEX frame file <embedded resource> // // Option settings: noParser, minimize @@ -16,8 +12,8 @@ // // -// Revised backup code -// Version 1.2.1 of 24-June-2013 +// Experimental embedded frame +// Version 1.1.3 of 18-April-2010 // // #define BACKUP @@ -126,15 +122,17 @@ namespace SimpleScanner enum Result {accept, noMatch, contextFound}; - const int maxAccept = 20; - const int initial = 21; + const int maxAccept = 35; + const int initial = 36; const int eofNum = 0; const int goStart = -1; const int INITIAL = 0; + const int COMMENT = 1; #region user code public int LexValueInt; public double LexValueDouble; + public string idsInComment = ""; #endregion user code int state; @@ -166,112 +164,178 @@ public int LexValueInt; } }; - static int[] startState = new int[] {21, 0}; + static int[] startState = new int[] {36, 39, 0}; - static Table[] NxS = new Table[23] { + static Table[] NxS = new Table[40] { /* 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, +/* NxS[ 2] */ new Table(39, 1, 38, new sbyte[] {25}), +/* NxS[ 3] */ new Table(47, 1, -1, new sbyte[] {24}), +/* NxS[ 4] */ new Table(46, 12, -1, new sbyte[] {37, -1, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4}), +/* NxS[ 5] */ new Table(61, 1, -1, new sbyte[] {22}), +/* NxS[ 6] */ new Table(0, 0, -1, null), +/* NxS[ 7] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 8] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 18, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 9] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 14, 7}), +/* NxS[ 10] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 12, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 11] */ new Table(0, 0, -1, null), +/* NxS[ 12] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 13, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 13] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 14] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 15, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 15] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 16, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 16] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 17, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 17] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 18] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 7, + 7, 19, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 19] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 20, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 20] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 21, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 21] */ new Table(48, 75, -1, new sbyte[] {7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, -1, -1, -1, -1, 7, -1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7}), +/* NxS[ 22] */ new Table(0, 0, -1, null), +/* NxS[ 23] */ new Table(48, 10, -1, new sbyte[] {23, 23, 23, 23, 23, 23, + 23, 23, 23, 23}), +/* NxS[ 24] */ new Table(10, 4, 24, new sbyte[] {-1, 24, 24, -1}), +/* NxS[ 25] */ new Table(0, 0, -1, null), +/* NxS[ 26] */ new Table(48, 75, -1, new sbyte[] {26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, -1, -1, -1, -1, 26, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26}), +/* NxS[ 27] */ new Table(48, 75, -1, new sbyte[] {26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, -1, -1, -1, -1, 26, -1, 26, 26, 26, 26, 32, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26}), +/* NxS[ 28] */ new Table(48, 75, -1, new sbyte[] {26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, -1, -1, -1, -1, 26, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26}), +/* NxS[ 29] */ new Table(0, 0, -1, null), +/* NxS[ 30] */ new Table(48, 75, -1, new sbyte[] {26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, -1, -1, -1, -1, 26, -1, 26, 26, 26, 31, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26}), +/* NxS[ 31] */ new Table(48, 75, -1, new sbyte[] {26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, -1, -1, -1, -1, 26, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26}), +/* NxS[ 32] */ new Table(48, 75, -1, new sbyte[] {26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, -1, -1, -1, -1, 26, -1, 26, 26, 26, 26, 26, + 26, 33, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26}), +/* NxS[ 33] */ new Table(48, 75, -1, new sbyte[] {26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, -1, -1, -1, -1, 26, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 34, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26}), +/* NxS[ 34] */ new Table(48, 75, -1, new sbyte[] {26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, -1, -1, -1, -1, 26, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 35, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26}), +/* NxS[ 35] */ new Table(48, 75, -1, new sbyte[] {26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, -1, -1, -1, -1, 26, -1, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26}), +/* NxS[ 36] */ new Table(10, 114, 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}), + -1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 1, 1, 1, 1, + 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, + 1, 7, 8, 9, 7, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 11}), +/* NxS[ 37] */ new Table(48, 10, -1, new sbyte[] {23, 23, 23, 23, 23, 23, + 23, 23, 23, 23}), +/* NxS[ 38] */ new Table(39, 1, 38, new sbyte[] {25}), +/* NxS[ 39] */ new Table(65, 61, -1, new sbyte[] {26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, 26, -1, 26, 27, 26, 26, 28, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, 29}), }; int NextState() { @@ -356,7 +420,8 @@ int NextState() { #if !NOFILES public Scanner(Stream file) { SetSource(file); // no unicode option - } + } + #endif // !NOFILES public Scanner() { } @@ -384,7 +449,7 @@ int NextState() { if (next < 0xDC00 || next > 0xDFFF) code = ScanBuff.UnicodeReplacementChar; else - code = (0x10000 + ((code & 0x3FF) << 10) + (next & 0x3FF)); + code = (0x10000 + (code & 0x3FF << 10) + (next & 0x3FF)); } #endif cCol++; @@ -437,7 +502,9 @@ int NextState() { GetCode(); } +#if !NOFILES // ================ LineBuffer Initialization =================== + /// <summary> /// Create and initialize a LineBuff buffer object for this scanner /// </summary> @@ -451,7 +518,6 @@ int NextState() { GetCode(); } -#if !NOFILES // =============== StreamBuffer Initialization ================== /// <summary> @@ -553,12 +619,6 @@ int NextState() { } } - /// <summary> - /// Discards all but the first "n" codepoints in the recognized pattern. - /// Resets the buffer position so that only n codepoints have been consumed; - /// yytext is also re-evaluated. - /// </summary> - /// <param name="n">The number of codepoints to consume</param> [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] void yyless(int n) { @@ -578,10 +638,6 @@ int NextState() { // but it does not seem possible to re-establish // the correct column counts except by going forward. // - /// <summary> - /// Removes the last "n" code points from the pattern. - /// </summary> - /// <param name="n">The number to remove</param> [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] void _yytrunc(int n) { yyless(yyleng - n); } @@ -594,23 +650,18 @@ int NextState() { // can't use (tokEPos - tokPos) because of the // possibility of surrogate pairs in the token. // - /// <summary> - /// The length of the pattern in codepoints (not the same as - /// string-length if the pattern contains any surrogate pairs). - /// </summary> [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 -#if BYTEMODE - return tokEPos - tokPos; -#else - { + else { int ch; int count = 0; int save = buffer.Pos; @@ -619,7 +670,7 @@ int NextState() { ch = buffer.Read(); if (!char.IsHighSurrogate((char)ch)) count++; } while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile); - buffer.Pos = save; + buffer.Pos = save; return count; } #endif // BYTEMODE @@ -644,55 +695,64 @@ int NextState() { // ============== The main tokenizer code ================= - int Scan() { - for (; ; ) { - int next; // next state to enter + int Scan() + { + for (; ; ) + { + int next; // next state to enter +#if BACKUP + Result rslt = Result.noMatch; +#endif // BACKUP #if LEFTANCHORS - for (;;) { + 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... + if ((next = NextState()) != goStart) + break; // LOOP EXIT HERE... GetCode(); } #else // !LEFTANCHORS state = currentStart; - while ((next = NextState()) == goStart) { + 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(); + GetCode(); + + while ((next = NextState()) > eofNum) // Exit for goStart AND for eofNum #if BACKUP - bool contextSaved = false; - while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum - if (state <= maxAccept && next > maxAccept) { // need to prepare backup data - // Store data for the *latest* accept state that was found. - SaveStateAndPos( ref ctx ); - contextSaved = true; + 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; } - state = next; - GetCode(); - } - if (state > maxAccept && contextSaved) - RestoreStateAndPos( ref ctx ); -#else // BACKUP - while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum - state = next; - GetCode(); - } + else #endif // BACKUP - if (state <= maxAccept) { + { + state = next; + GetCode(); + } + if (state <= maxAccept) + { MarkEnd(); #region ActionSwitch -#pragma warning disable 162, 1522 +#pragma warning disable 162 switch (state) { case eofNum: @@ -700,59 +760,111 @@ int NextState() { return (int)Tokens.EOF; break; case 1: + case 2: + case 3: LexError(); return 0; break; - case 2: + case 4: LexValueInt = int.Parse(yytext); return (int)Tok.INUM; break; - case 3: + case 5: return (int)Tok.COLON; break; - case 4: + case 6: return (int)Tok.SEMICOLON; break; - case 5: - case 6: case 7: case 8: case 9: - case 11: + case 10: case 12: - case 13: + case 14: case 15: case 16: - case 17: + case 18: + case 19: + case 20: return (int)Tok.ID; break; - case 10: + case 11: +BEGIN(COMMENT); + break; + case 13: return (int)Tok.END; break; - case 14: + case 17: return (int)Tok.CYCLE; break; - case 18: + case 21: return (int)Tok.BEGIN; break; - case 19: + case 22: return (int)Tok.ASSIGN; break; - case 20: + case 23: LexValueDouble = double.Parse(yytext); return (int)Tok.RNUM; break; + case 24: +return (int)Tok.COMMENT; + break; + case 25: +return (int)Tok.STRINGAP; + break; + case 26: + case 27: + case 28: + case 30: + case 32: + case 33: + case 34: +idsInComment = yytext; + return (int)Tok.LONGCOMMENT; + break; + case 29: +BEGIN(INITIAL); + break; + case 31: +return (int)Tok.END; + break; + case 35: +return (int)Tok.BEGIN; + break; default: break; } -#pragma warning restore 162, 1522 +#pragma warning restore 162 #endregion } } } #if BACKUP - void SaveStateAndPos(ref Context ctx) { + 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; @@ -761,7 +873,8 @@ LexValueDouble = double.Parse(yytext); ctx.cChr = code; } - void RestoreStateAndPos(ref Context ctx) { + void RestoreStateAndPos(ref Context ctx) + { buffer.Pos = ctx.bPos; readPos = ctx.rPos; cCol = ctx.cCol; @@ -769,7 +882,8 @@ LexValueDouble = double.Parse(yytext); state = ctx.state; code = ctx.cChr; } -#endif // BACKUP + +#endif // BACKUP // ============= End of the tokenizer code ================ @@ -803,7 +917,7 @@ LexValueDouble = double.Parse(yytext); public void LexError() { - Console.WriteLine("({0},{1}): ÍåèçâåñòГûé ñèìâîë {2}", yyline, yycol, yytext); + Console.WriteLine("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); } public string TokToString(Tok tok) @@ -870,7 +984,6 @@ public string TokToString(Tok tok) return new LineBuffer(source); } -#if (!NOFILES) public static ScanBuff GetBuffer(Stream source) { return new BuildBuffer(source); @@ -881,8 +994,7 @@ public string TokToString(Tok tok) { return new BuildBuffer(source, fallbackCodePage); } -#endif // !BYTEMODE -#endif // !NOFILES +#endif } #region Buffer classes @@ -1005,7 +1117,7 @@ public string TokToString(Tok tok) { ix = lstart = 0; } - while (ix < numLines) + for (; ; ) { int len = line[ix].Length + 1; if (pos < lstart + len) break; @@ -1063,8 +1175,7 @@ public string TokToString(Tok tok) { cPos = value; findIndex(cPos, out cLine, out curLineStart); - // cLine should be the *next* line after curLine. - curLine = (cLine < numLines ? line[cLine++] : ""); + curLine = line[cLine]; curLineEnd = curLineStart + curLine.Length; } } @@ -1072,7 +1183,7 @@ public string TokToString(Tok tok) public override string ToString() { return "LineBuffer"; } } -#if (!NOFILES) + // ============================================================== // ===== class BuildBuff : for unicode text files ======== // ============================================================== @@ -1313,13 +1424,12 @@ public string TokToString(Tok tok) } #endif // !BYTEMODE } -#endif // !NOFILES #endregion Buffer classes // ============================================================== // ============ class CodePageHandling ============= // ============================================================== -#if (!NOFILES) + public static class CodePageHandling { public static int GetCodePage(string option) @@ -1530,7 +1640,6 @@ public string TokToString(Tok tok) #endif // !BYTEMODE #endregion -#endif // !NOFILES // End of code copied from embedded resource diff --git a/Module3/SimpleLex.lex b/Module3/SimpleLex.lex index c0434f0..4b32853 100644 --- a/Module3/SimpleLex.lex +++ b/Module3/SimpleLex.lex @@ -7,14 +7,50 @@ AlphaDigit {Alpha}|{Digit} INTNUM {Digit}+ REALNUM {INTNUM}\.{INTNUM} ID {Alpha}{AlphaDigit}* +DotChr [^\r\n] +OneLineCmnt \/\/{DotChr}* +Apostrophe \'[^']*\' + + + +%x COMMENT // Здесь можно делать описания типов, переменных и методов - они попадают в класс Scanner %{ public int LexValueInt; public double LexValueDouble; + public string idsInComment = ""; %} + + %% + +"{" { + // COMMENT + BEGIN(COMMENT); +} + +<COMMENT> "}" { + // переход в состояние INITIAL (исходное) + BEGIN(INITIAL); +} + +<COMMENT>begin { + return (int)Tok.BEGIN; +} + +<COMMENT>end { + return (int)Tok.END; +} + +<COMMENT>{ID} { + idsInComment = yytext; + return (int)Tok.LONGCOMMENT; +} + + + {INTNUM} { LexValueInt = int.Parse(yytext); return (int)Tok.INUM; @@ -41,6 +77,16 @@ cycle { return (int)Tok.ID; } +{OneLineCmnt} { + return (int)Tok.COMMENT; +} + +{Apostrophe} { + return (int)Tok.STRINGAP; +} + + + ":" { return (int)Tok.COLON; } @@ -58,6 +104,7 @@ cycle { return 0; // конец разбора } + %% // Здесь можно делать описания переменных и методов - они тоже попадают в класс Scanner diff --git a/Module3/SimpleLex.lst b/Module3/SimpleLex.lst new file mode 100644 index 0000000..e6ee401 --- /dev/null +++ b/Module3/SimpleLex.lst @@ -0,0 +1,141 @@ + +// ========================================================================== +// GPLEX error listing for lex source file <SimpleLex.lex> +// ========================================================================== +// Version: 1.1.3.301 +// Machine: WIN-51KGPO1PTR9 +// DateTime: 27.11.2022 17:27:41 +// UserName: ????????????? +// ========================================================================== + + +%using ScannerHelper; +%namespace SimpleScanner + +Alpha [a-zA-Z_] +Digit [0-9] +AlphaDigit {Alpha}|{Digit} +INTNUM {Digit}+ +REALNUM {INTNUM}\.{INTNUM} +ID {Alpha}{AlphaDigit}* +DotChr [^\r\n] +OneLineCmnt \/\/{DotChr}* +Apostrophe \'[^']*\' + + + +%x COMMENT + +// Здесь можно делать описания типов, переменных и методов - они попадают в класс Scanner +%{ + public int LexValueInt; + public double LexValueDouble; + public List<string> commentedIDs = new List<string>(); +%} + + + +%% +{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; +} + +{OneLineCmnt} { + return (int)Tok.COMMENT; +} + +{Apostrophe} { + return (int)Tok.STRINGAP; +} + + + +":" { + return (int)Tok.COLON; +} + +":=" { + return (int)Tok.ASSIGN; +} + +";" { + return (int)Tok.SEMICOLON; +} + +[^ \r\n] { +//^^^^^^ +// Warning: This pattern always overrides ""{"" +// --------------------------------------------- + LexError(); + return 0; // конец разбора +} + +"{" { +// Warning: This pattern always overridden by "[^ \r\n]" +// ------------------------------------------------------ + // переход в состояние COMMENT + BEGIN(COMMENT); +} + +<COMMENT> "}" { + // переход в состояние INITIAL (исходное) + BEGIN(INITIAL); +} + +<COMMENT>{ID} { + if (yytext != "begin" && yytext != "end" && yytext != "cycle") { + commentedIDs.Add(yytext); + } + + return (int)Tok.LONGCOMMENT; +} + + +%% + +// Здесь можно делать описания переменных и методов - они тоже попадают в класс 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/a.txt b/Module3/a.txt index cda6431..9db1d29 100644 --- a/Module3/a.txt +++ b/Module3/a.txt @@ -1,3 +1,3 @@ -begin ggg : ; :+= 7 99.9 5 -1 +begin gggggg ppp : ; : 7 99.9 5 +1 2 ppp end diff --git a/Module3/mymain.cs b/Module3/mymain.cs index 9a33c59..d9f67b1 100644 --- a/Module3/mymain.cs +++ b/Module3/mymain.cs @@ -12,7 +12,8 @@ namespace GeneratedLexer { int cnt_id = 0;//кол-во идентификаторов int min_id_len = Int32.MaxValue, max_id_len = 0; //минимальная, максимальная длины идентификаторов - double avg_id_len = 0; //средняя длина идентификатора + + int sum_id_len = 0; //sum длина идентификатора int sum_int = 0; //сумма всех целых double sum_d = 0; //сумма всех вещественных @@ -34,9 +35,9 @@ namespace GeneratedLexer { Console.WriteLine(); Console.WriteLine("number of id: {0:D}", cnt_id); - Console.WriteLine("average length of the id: {0:N}", avg_id_len / cnt_id); + Console.WriteLine("average length of the id: {0:N}", sum_id_len / cnt_id); Console.WriteLine("min length of the id: {0:D}", min_id_len); - Console.WriteLine("min length of the id: {0:D}", max_id_len); + Console.WriteLine("max length of the id: {0:D}", max_id_len); Console.WriteLine(); Console.WriteLine("sum of int: {0:D}", sum_int); @@ -46,6 +47,23 @@ namespace GeneratedLexer break; } + else if (tok == (int)Tok.ID) + { + cnt_id++; + int length = scanner.yytext.Length; + sum_id_len += length; + min_id_len = length < min_id_len ? length : min_id_len; + max_id_len = length > max_id_len ? length : max_id_len; + } + else if (tok == (int)Tok.INUM) + { + sum_int += scanner.LexValueInt; + } + else if (tok == (int)Tok.RNUM) + { + sum_d += scanner.LexValueDouble; + } + Console.WriteLine(scanner.TokToString((Tok)tok)); } while (true); diff --git a/Module3/packages.config b/Module3/packages.config new file mode 100644 index 0000000..e68db37 --- /dev/null +++ b/Module3/packages.config @@ -0,0 +1,6 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> +</packages> \ No newline at end of file diff --git a/Module4/SimpleLangParser/RecursiveDescentParser.csproj b/Module4/SimpleLangParser/RecursiveDescentParser.csproj index 62fc781..7375ec7 100644 --- a/Module4/SimpleLangParser/RecursiveDescentParser.csproj +++ b/Module4/SimpleLangParser/RecursiveDescentParser.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\..\packages\NUnit.3.12.0\build\NUnit.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> @@ -12,6 +14,8 @@ <TargetFrameworkVersion>v4.8</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <TargetFrameworkProfile /> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> @@ -41,6 +45,9 @@ <Reference Include="Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <HintPath>C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.dll</HintPath> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> @@ -58,7 +65,17 @@ <Name>SimpleLexer</Name> </ProjectReference> </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> <!-- 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"> diff --git a/Module4/SimpleLangParser/SimpleLangParser.cs b/Module4/SimpleLangParser/SimpleLangParser.cs index 246db0b..06387d3 100644 --- a/Module4/SimpleLangParser/SimpleLangParser.cs +++ b/Module4/SimpleLangParser/SimpleLangParser.cs @@ -27,7 +27,7 @@ namespace SimpleLangParser Block(); } - public void Expr() + public void Expr2() { if (l.LexKind == Tok.ID || l.LexKind == Tok.INUM) { @@ -39,6 +39,66 @@ namespace SimpleLangParser } } + // ==== другая грамматика ==== + + public void Expr() + { + T(); + A(); + } + + public void T() + { + M(); + B(); + } + + public void A() + { + if (l.LexKind == Tok.PLUS || l.LexKind == Tok.MINUS) + { + l.NextLexem(); // РїСЂРѕРїСѓСЃРє sign + T(); + A(); + } + } + + public void B() + { + if (l.LexKind == Tok.MULT || l.LexKind == Tok.DIVISION) + { + l.NextLexem(); + M(); + B(); + } + } + public void M() + { + if (l.LexKind == Tok.ID || l.LexKind == Tok.INUM) + { + l.NextLexem(); + } + else if (l.LexKind == Tok.LEFT_BRACKET) + { + l.NextLexem(); // РїСЂРѕРїСѓСЃРє ( + Expr(); + if (l.LexKind != Tok.RIGHT_BRACKET) + { + SyntaxError(") expected"); + } + l.NextLexem(); + } + else + { + SyntaxError("ID, number or (expr) expected"); + } + } + + + + // ==== другая грамматика ==== + + public void Assign() { l.NextLexem(); // РїСЂРѕРїСѓСЃРє id @@ -81,6 +141,22 @@ namespace SimpleLangParser Assign(); break; } + case Tok.WHILE: + { + While(); + break; + } + case Tok.FOR: + { + For(); + break; + } + case Tok.IF: + { + If(); + break; + } + default: { SyntaxError("Operator expected"); @@ -111,6 +187,66 @@ namespace SimpleLangParser Statement(); } + public void While() + { + l.NextLexem(); // РїСЂРѕРїСѓСЃРє while + Expr(); + if (l.LexKind != Tok.DO) + { + SyntaxError("do expected"); + } + + l.NextLexem(); // РїСЂРѕРїСѓСЃРє do + Statement(); + } + + public void For() + { + l.NextLexem(); // РїСЂРѕРїСѓСЃРє for + if (l.LexKind != Tok.ID) + { + SyntaxError("id expected"); + } + Assign(); + + if (l.LexKind != Tok.TO) + { + SyntaxError("to expected"); + } + + l.NextLexem(); // РїСЂРѕРїСѓСЃРє TO + Expr(); + if (l.LexKind != Tok.DO) + { + SyntaxError("do expected"); + } + + l.NextLexem(); // РїСЂРѕРїСѓСЃРє DO + Statement(); + } + + public void If() + { + l.NextLexem(); // РїСЂРѕРїСѓСЃРє if + Expr(); + + if (l.LexKind != Tok.THEN) + { + SyntaxError("then expected"); + } + + l.NextLexem(); // РїСЂРѕРїСѓСЃРє then + Statement(); + if (l.LexKind != Tok.ELSE) + { + return; // если неполная форма РІСЃС‘ РѕРє - РЅРµ выкидываем SyntaxError + } + l.NextLexem(); // РїСЂРѕРїСѓСЃРє else + Statement(); + } + + + public void SyntaxError(string message) { var errorMessage = "Syntax error in line " + l.LexRow.ToString() + ":\n"; diff --git a/Module4/SimpleLangParser/packages.config b/Module4/SimpleLangParser/packages.config new file mode 100644 index 0000000..e68db37 --- /dev/null +++ b/Module4/SimpleLangParser/packages.config @@ -0,0 +1,6 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> +</packages> \ No newline at end of file diff --git a/Module4/SimpleLangParserTest/RecursiveDescentParserDemo.csproj b/Module4/SimpleLangParserTest/RecursiveDescentParserDemo.csproj index ff254b8..fd91524 100644 --- a/Module4/SimpleLangParserTest/RecursiveDescentParserDemo.csproj +++ b/Module4/SimpleLangParserTest/RecursiveDescentParserDemo.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\..\packages\NUnit.3.12.0\build\NUnit.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> @@ -12,6 +14,8 @@ <TargetFrameworkVersion>v4.8</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <TargetFrameworkProfile /> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> @@ -41,6 +45,9 @@ <Reference Include="Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <HintPath>C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.dll</HintPath> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> @@ -64,8 +71,16 @@ </ItemGroup> <ItemGroup> <None Include="app.config" /> + <None Include="packages.config" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> <!-- 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"> diff --git a/Module4/SimpleLangParserTest/packages.config b/Module4/SimpleLangParserTest/packages.config new file mode 100644 index 0000000..e68db37 --- /dev/null +++ b/Module4/SimpleLangParserTest/packages.config @@ -0,0 +1,6 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> +</packages> \ No newline at end of file diff --git a/Module5/GeneratedParser.csproj b/Module5/GeneratedParser.csproj index 6928965..ecefaf8 100644 --- a/Module5/GeneratedParser.csproj +++ b/Module5/GeneratedParser.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">x86</Platform> @@ -14,6 +16,8 @@ <TargetFrameworkProfile> </TargetFrameworkProfile> <FileAlignment>512</FileAlignment> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PlatformTarget>x86</PlatformTarget> @@ -60,6 +64,9 @@ <Reference Include="Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <HintPath>C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.dll</HintPath> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> @@ -83,8 +90,16 @@ </ItemGroup> <ItemGroup> <None Include="app.config" /> + <None Include="packages.config" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> <!-- 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"> diff --git a/Module5/SimpleLex.cs b/Module5/SimpleLex.cs index af473da..dc2b032 100644 --- a/Module5/SimpleLex.cs +++ b/Module5/SimpleLex.cs @@ -1,14 +1,10 @@ // // This CSharp output file generated by Gardens Point LEX -// Gardens Point LEX (GPLEX) is Copyright (c) John Gough, QUT 2006-2014. -// Output produced by GPLEX is the property of the user. -// See accompanying file GPLEXcopyright.rtf. -// -// GPLEX Version: 1.2.2 -// Machine: MAINHOMEPC2 -// DateTime: 30.09.2018 18:11:00 -// UserName: someone -// GPLEX input file <SimpleLex.lex - 24.09.2018 23:47:02> +// Version: 1.1.3.301 +// Machine: WIN-51KGPO1PTR9 +// DateTime: 28.11.2022 22:08:30 +// UserName: ????????????? +// GPLEX input file <SimpleLex.lex> // GPLEX frame file <embedded resource> // // Option settings: unicode, parser, minimize @@ -17,8 +13,8 @@ // // -// Revised backup code -// Version 1.2.1 of 24-June-2013 +// Experimental embedded frame +// Version 1.1.3 of 18-April-2010 // // #define BACKUP @@ -127,8 +123,8 @@ namespace SimpleScanner enum Result {accept, noMatch, contextFound}; - const int maxAccept = 7; - const int initial = 8; + const int maxAccept = 14; + const int initial = 15; const int eofNum = 0; const int goStart = -1; const int INITIAL = 0; @@ -165,24 +161,24 @@ namespace SimpleScanner } }; - static int[] startState = new int[] {8, 0}; + static int[] startState = new int[] {15, 0}; #region CompressedCharacterMap // - // There are 8 equivalence classes + // 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' */ 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, +/* '\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, 7, 8, 12, 10, 9, 11, 2, 13, +/* '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) @@ -190,22 +186,29 @@ namespace SimpleScanner if (code < 123) // '\0' <= code <= 'z' return mapC0[code - 0]; else // '{' <= code <= '\U0010FFFF' - return (sbyte)7; + return (sbyte)14; } #endregion - static Table[] NxS = new Table[10] { + static Table[] NxS = new Table[17] { /* NxS[ 0] */ new Table(0, 0, 0, null), -/* NxS[ 1] */ new Table(1, 2, -1, new sbyte[] {1, 9}), +/* NxS[ 1] */ new Table(1, 2, -1, new sbyte[] {1, 16}), /* 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[ 4] */ new Table(5, 1, -1, new sbyte[] {13}), /* 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}), +/* NxS[ 7] */ new Table(0, 0, -1, null), +/* NxS[ 8] */ new Table(0, 0, -1, null), +/* 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(1, 1, -1, new sbyte[] {14}), +/* NxS[ 15] */ new Table(1, 14, -1, new sbyte[] {1, 2, 3, 4, 2, 5, + 6, 7, 8, 9, 10, 11, 12, 2}), +/* NxS[ 16] */ new Table(1, 1, -1, new sbyte[] {14}), }; int NextState() { @@ -215,7 +218,7 @@ int NextState() { unchecked { int rslt; int idx = MapC(code) - NxS[state].min; - if (idx < 0) idx += 8; + if (idx < 0) idx += 15; if ((uint)idx >= (uint)NxS[state].rng) rslt = NxS[state].dflt; else rslt = NxS[state].nxt[idx]; return rslt; @@ -295,7 +298,8 @@ int NextState() { public Scanner(Stream file, string codepage) { SetSource(file, CodePageHandling.GetCodePage(codepage)); - } + } + #endif // !NOFILES public Scanner() { } @@ -323,7 +327,7 @@ int NextState() { if (next < 0xDC00 || next > 0xDFFF) code = ScanBuff.UnicodeReplacementChar; else - code = (0x10000 + ((code & 0x3FF) << 10) + (next & 0x3FF)); + code = (0x10000 + (code & 0x3FF << 10) + (next & 0x3FF)); } #endif cCol++; @@ -376,7 +380,9 @@ int NextState() { GetCode(); } +#if !NOFILES // ================ LineBuffer Initialization =================== + /// <summary> /// Create and initialize a LineBuff buffer object for this scanner /// </summary> @@ -390,7 +396,6 @@ int NextState() { GetCode(); } -#if !NOFILES // =============== StreamBuffer Initialization ================== /// <summary> @@ -492,12 +497,6 @@ int NextState() { } } - /// <summary> - /// Discards all but the first "n" codepoints in the recognized pattern. - /// Resets the buffer position so that only n codepoints have been consumed; - /// yytext is also re-evaluated. - /// </summary> - /// <param name="n">The number of codepoints to consume</param> [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] void yyless(int n) { @@ -517,10 +516,6 @@ int NextState() { // but it does not seem possible to re-establish // the correct column counts except by going forward. // - /// <summary> - /// Removes the last "n" code points from the pattern. - /// </summary> - /// <param name="n">The number to remove</param> [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] void _yytrunc(int n) { yyless(yyleng - n); } @@ -533,23 +528,18 @@ int NextState() { // can't use (tokEPos - tokPos) because of the // possibility of surrogate pairs in the token. // - /// <summary> - /// The length of the pattern in codepoints (not the same as - /// string-length if the pattern contains any surrogate pairs). - /// </summary> [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 -#if BYTEMODE - return tokEPos - tokPos; -#else - { + else { int ch; int count = 0; int save = buffer.Pos; @@ -558,7 +548,7 @@ int NextState() { ch = buffer.Read(); if (!char.IsHighSurrogate((char)ch)) count++; } while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile); - buffer.Pos = save; + buffer.Pos = save; return count; } #endif // BYTEMODE @@ -583,56 +573,65 @@ int NextState() { // ============== The main tokenizer code ================= - int Scan() { + int Scan() + { try { - for (; ; ) { - int next; // next state to enter + for (; ; ) + { + int next; // next state to enter +#if BACKUP + Result rslt = Result.noMatch; +#endif // BACKUP #if LEFTANCHORS - for (;;) { + 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... + if ((next = NextState()) != goStart) + break; // LOOP EXIT HERE... GetCode(); } #else // !LEFTANCHORS state = currentStart; - while ((next = NextState()) == goStart) { + 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(); + GetCode(); + + while ((next = NextState()) > eofNum) // Exit for goStart AND for eofNum #if BACKUP - bool contextSaved = false; - while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum - if (state <= maxAccept && next > maxAccept) { // need to prepare backup data - // Store data for the *latest* accept state that was found. - SaveStateAndPos( ref ctx ); - contextSaved = true; + 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; } - state = next; - GetCode(); - } - if (state > maxAccept && contextSaved) - RestoreStateAndPos( ref ctx ); -#else // BACKUP - while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum - state = next; - GetCode(); - } + else #endif // BACKUP - if (state <= maxAccept) { + { + state = next; + GetCode(); + } + if (state <= maxAccept) + { MarkEnd(); #region ActionSwitch -#pragma warning disable 162, 1522 +#pragma warning disable 162 switch (state) { case eofNum: @@ -655,15 +654,36 @@ int res = ScannerHelper.GetIDToken(yytext); return (int)Tokens.SEMICOLON; break; case 6: -return (int)Tokens.ASSIGN; +return (int)Tokens.LEFT_BRACKET; break; case 7: +return (int)Tokens.RIGHT_BRACKET; + break; + case 8: +return (int)Tokens.COMMA; + break; + case 9: +return (int)Tokens.PLUS; + break; + case 10: +return (int)Tokens.MINUS; + break; + case 11: +return (int)Tokens.MULT; + break; + case 12: +return (int)Tokens.DIV; + break; + case 13: +return (int)Tokens.ASSIGN; + break; + case 14: return (int)Tokens.RNUM; break; default: break; } -#pragma warning restore 162, 1522 +#pragma warning restore 162 #endregion } } @@ -676,7 +696,29 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); } #if BACKUP - void SaveStateAndPos(ref Context ctx) { + 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; @@ -685,7 +727,8 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); ctx.cChr = code; } - void RestoreStateAndPos(ref Context ctx) { + void RestoreStateAndPos(ref Context ctx) + { buffer.Pos = ctx.bPos; readPos = ctx.rPos; cCol = ctx.cCol; @@ -693,7 +736,8 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); state = ctx.state; code = ctx.cChr; } -#endif // BACKUP + +#endif // BACKUP // ============= End of the tokenizer code ================ @@ -725,16 +769,16 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); #region UserCodeSection -public override void yyerror(string format, params object[] args) // îáðà áîòêà ñèГГІГ ГЄГ±ГЁГ·ГҐГ±ГЄГЁГµ îøèáîê +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)); + 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); + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); throw new LexException(errorMsg); } @@ -748,10 +792,23 @@ class ScannerHelper keywords.Add("begin",(int)Tokens.BEGIN); keywords.Add("end",(int)Tokens.END); keywords.Add("cycle",(int)Tokens.CYCLE); + keywords.Add("while",(int)Tokens.WHILE); + keywords.Add("do",(int)Tokens.DO); + keywords.Add("repeat",(int)Tokens.REPEAT); + keywords.Add("until",(int)Tokens.UNTIL); + keywords.Add("for", (int)Tokens.FOR); + keywords.Add("to", (int)Tokens.TO); + keywords.Add("write", (int)Tokens.WRITE); + keywords.Add("if", (int)Tokens.IF); + keywords.Add("then", (int)Tokens.THEN); + keywords.Add("else", (int)Tokens.ELSE); + keywords.Add("var",(int)Tokens.VAR); + + } public static int GetIDToken(string s) { - if (keywords.ContainsKey(s.ToLower())) // ÿçûê Гå÷óâñòâèòåëåà ê ðåãèñòðó + if (keywords.ContainsKey(s.ToLower())) // язык нечувствителен к регистру return keywords[s]; else return (int)Tokens.ID; @@ -807,7 +864,6 @@ class ScannerHelper return new LineBuffer(source); } -#if (!NOFILES) public static ScanBuff GetBuffer(Stream source) { return new BuildBuffer(source); @@ -818,8 +874,7 @@ class ScannerHelper { return new BuildBuffer(source, fallbackCodePage); } -#endif // !BYTEMODE -#endif // !NOFILES +#endif } #region Buffer classes @@ -942,7 +997,7 @@ class ScannerHelper { ix = lstart = 0; } - while (ix < numLines) + for (; ; ) { int len = line[ix].Length + 1; if (pos < lstart + len) break; @@ -1000,8 +1055,7 @@ class ScannerHelper { cPos = value; findIndex(cPos, out cLine, out curLineStart); - // cLine should be the *next* line after curLine. - curLine = (cLine < numLines ? line[cLine++] : ""); + curLine = line[cLine]; curLineEnd = curLineStart + curLine.Length; } } @@ -1009,7 +1063,7 @@ class ScannerHelper public override string ToString() { return "LineBuffer"; } } -#if (!NOFILES) + // ============================================================== // ===== class BuildBuff : for unicode text files ======== // ============================================================== @@ -1250,13 +1304,12 @@ class ScannerHelper } #endif // !BYTEMODE } -#endif // !NOFILES #endregion Buffer classes // ============================================================== // ============ class CodePageHandling ============= // ============================================================== -#if (!NOFILES) + public static class CodePageHandling { public static int GetCodePage(string option) @@ -1467,7 +1520,6 @@ class ScannerHelper #endif // !BYTEMODE #endregion -#endif // !NOFILES // End of code copied from embedded resource diff --git a/Module5/SimpleLex.lex b/Module5/SimpleLex.lex index 10547e9..486ba02 100644 --- a/Module5/SimpleLex.lex +++ b/Module5/SimpleLex.lex @@ -28,6 +28,15 @@ ID {Alpha}{AlphaDigit}* ":=" { return (int)Tokens.ASSIGN; } ";" { return (int)Tokens.SEMICOLON; } +"(" { return (int)Tokens.LEFT_BRACKET; } +")" { return (int)Tokens.RIGHT_BRACKET; } +"," { return (int)Tokens.COMMA; } +"+" { return (int)Tokens.PLUS; } +"-" { return (int)Tokens.MINUS; } +"*" { return (int)Tokens.MULT; } +"/" { return (int)Tokens.DIV; } + + [^ \r\n] { LexError(); @@ -63,6 +72,19 @@ class ScannerHelper keywords.Add("begin",(int)Tokens.BEGIN); keywords.Add("end",(int)Tokens.END); keywords.Add("cycle",(int)Tokens.CYCLE); + keywords.Add("while",(int)Tokens.WHILE); + keywords.Add("do",(int)Tokens.DO); + keywords.Add("repeat",(int)Tokens.REPEAT); + keywords.Add("until",(int)Tokens.UNTIL); + keywords.Add("for", (int)Tokens.FOR); + keywords.Add("to", (int)Tokens.TO); + keywords.Add("write", (int)Tokens.WRITE); + keywords.Add("if", (int)Tokens.IF); + keywords.Add("then", (int)Tokens.THEN); + keywords.Add("else", (int)Tokens.ELSE); + keywords.Add("var",(int)Tokens.VAR); + + } public static int GetIDToken(string s) { diff --git a/Module5/SimpleYacc.cs b/Module5/SimpleYacc.cs index 0be7914..d90f58e 100644 --- a/Module5/SimpleYacc.cs +++ b/Module5/SimpleYacc.cs @@ -1,102 +1,161 @@ // This code was generated by the Gardens Point Parser Generator -// Copyright (c) Wayne Kelly, John Gough, QUT 2005-2014 +// Copyright (c) Wayne Kelly, QUT 2005-2010 // (see accompanying GPPGcopyright.rtf) -// GPPG version 1.5.2 -// Machine: MAINHOMEPC2 -// DateTime: 30.09.2018 18:11:19 -// UserName: someone -// Input file <SimpleYacc.y - 24.09.2018 23:47:02> +// GPPG version 1.3.6 +// Machine: WIN-51KGPO1PTR9 +// DateTime: 28.11.2022 22:08:30 +// UserName: ????????????? +// Input file <SimpleYacc.y> // options: no-lines gplex using System; using System.Collections.Generic; -using System.CodeDom.Compiler; using System.Globalization; using System.Text; using QUT.Gppg; namespace SimpleParser { -public enum Tokens {error=2,EOF=3,BEGIN=4,END=5,CYCLE=6, - INUM=7,RNUM=8,ID=9,ASSIGN=10,SEMICOLON=11}; +public enum Tokens { + error=1,EOF=2,BEGIN=3,END=4,CYCLE=5,INUM=6, + RNUM=7,ID=8,ASSIGN=9,SEMICOLON=10,WHILE=11,DO=12, + REPEAT=13,UNTIL=14,FOR=15,TO=16,WRITE=17,LEFT_BRACKET=18, + RIGHT_BRACKET=19,IF=20,THEN=21,ELSE=22,VAR=23,COMMA=24, + PLUS=25,MINUS=26,MULT=27,DIV=28}; // Abstract base class for GPLEX scanners -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] 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; } } -// Utility class for encapsulating token information -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] -public class ScanObj { - public int token; - public int yylval; - public LexLocation yylloc; - public ScanObj( int t, int val, LexLocation loc ) { - this.token = t; this.yylval = val; this.yylloc = loc; - } -} - -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] public class Parser: ShiftReduceParser<int, LexLocation> { - // Verbatim content from SimpleYacc.y - 24.09.2018 23:47:02 -// ГќГІГЁ îáúÿâëåГГЁГї äîáà âëÿþòñÿ Гў êëà ññ GPPGParser, ïðåäñòà âëÿþùèé ñîáîé ïà ðñåð, ГЈГҐГåðèðóåìûé ñèñòåìîé gppg + // Verbatim content from SimpleYacc.y +// Эти объявления добавляются в класс GPPGParser, представляющий собой парсер, генерируемый системой gppg public Parser(AbstractScanner<int, LexLocation> scanner) : base(scanner) { } - // End verbatim content from SimpleYacc.y - 24.09.2018 23:47:02 + // End verbatim content from SimpleYacc.y #pragma warning disable 649 - private static Dictionary<int, string> aliases; + 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 Rule[] rules = new Rule[36]; + private static State[] states = new State[70]; private static string[] nonTerms = new string[] { "progr", "$accept", "block", "stlist", "statement", "assign", "cycle", - "ident", "expr", }; + "while", "repeat", "for", "write", "if", "var", "ident", "expr", "t", "f", + "id_list", }; static Parser() { - states[0] = new State(new int[]{4,4},new int[]{-1,1,-3,3}); - states[1] = new State(new int[]{3,2}); + 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[]{9,14,4,4,6,18},new int[]{-4,5,-5,21,-6,9,-8,10,-3,16,-7,17}); - states[5] = new State(new int[]{5,6,11,7}); - states[6] = new State(-12); - states[7] = new State(new int[]{9,14,4,4,6,18},new int[]{-5,8,-6,9,-8,10,-3,16,-7,17}); + states[4] = new State(new int[]{8,18,3,4,5,31,11,35,13,40,15,46,17,53,20,58,23,65},new int[]{-4,5,-5,44,-6,9,-14,10,-3,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[5] = new State(new int[]{4,6,10,7}); + states[6] = new State(-25); + states[7] = new State(new int[]{8,18,3,4,5,31,11,35,13,40,15,46,17,53,20,58,23,65},new int[]{-5,8,-6,9,-14,10,-3,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); states[8] = new State(-4); states[9] = new State(-5); - states[10] = new State(new int[]{10,11}); - states[11] = new State(new int[]{9,14,7,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[]{9,14,7,15},new int[]{-9,19,-8,13}); - states[19] = new State(new int[]{9,14,4,4,6,18},new int[]{-5,20,-6,9,-8,10,-3,16,-7,17}); - states[20] = new State(-13); - states[21] = new State(-3); - - for (int sNo = 0; sNo < states.Length; sNo++) states[sNo].number = sNo; + states[10] = new State(new int[]{9,11}); + states[11] = new State(new int[]{8,18,6,19,18,20},new int[]{-15,12,-16,28,-17,27,-14,17}); + states[12] = new State(new int[]{25,13,26,23,4,-15,10,-15,14,-15,22,-15,16,-15}); + states[13] = new State(new int[]{8,18,6,19,18,20},new int[]{-16,14,-17,27,-14,17}); + states[14] = new State(new int[]{27,15,28,25,25,-17,26,-17,4,-17,10,-17,14,-17,22,-17,16,-17,19,-17,8,-17,3,-17,5,-17,11,-17,13,-17,15,-17,17,-17,20,-17,23,-17,12,-17,21,-17}); + states[15] = new State(new int[]{8,18,6,19,18,20},new int[]{-17,16,-14,17}); + states[16] = new State(-20); + states[17] = new State(-22); + states[18] = new State(-14); + states[19] = new State(-23); + states[20] = new State(new int[]{8,18,6,19,18,20},new int[]{-15,21,-16,28,-17,27,-14,17}); + states[21] = new State(new int[]{19,22,25,13,26,23}); + states[22] = new State(-24); + states[23] = new State(new int[]{8,18,6,19,18,20},new int[]{-16,24,-17,27,-14,17}); + states[24] = new State(new int[]{27,15,28,25,25,-18,26,-18,4,-18,10,-18,14,-18,22,-18,16,-18,19,-18,8,-18,3,-18,5,-18,11,-18,13,-18,15,-18,17,-18,20,-18,23,-18,12,-18,21,-18}); + states[25] = new State(new int[]{8,18,6,19,18,20},new int[]{-17,26,-14,17}); + states[26] = new State(-21); + states[27] = new State(-19); + states[28] = new State(new int[]{27,15,28,25,25,-16,26,-16,4,-16,10,-16,14,-16,22,-16,16,-16,19,-16,8,-16,3,-16,5,-16,11,-16,13,-16,15,-16,17,-16,20,-16,23,-16,12,-16,21,-16}); + states[29] = new State(-6); + states[30] = new State(-7); + states[31] = new State(new int[]{8,18,6,19,18,20},new int[]{-15,32,-16,28,-17,27,-14,17}); + states[32] = new State(new int[]{25,13,26,23,8,18,3,4,5,31,11,35,13,40,15,46,17,53,20,58,23,65},new int[]{-5,33,-6,9,-14,10,-3,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[33] = new State(-26); + states[34] = new State(-8); + states[35] = new State(new int[]{8,18,6,19,18,20},new int[]{-15,36,-16,28,-17,27,-14,17}); + states[36] = new State(new int[]{12,37,25,13,26,23}); + states[37] = new State(new int[]{8,18,3,4,5,31,11,35,13,40,15,46,17,53,20,58,23,65},new int[]{-5,38,-6,9,-14,10,-3,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[38] = new State(-27); + states[39] = new State(-9); + states[40] = new State(new int[]{8,18,3,4,5,31,11,35,13,40,15,46,17,53,20,58,23,65},new int[]{-4,41,-5,44,-6,9,-14,10,-3,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[41] = new State(new int[]{14,42,10,7}); + states[42] = new State(new int[]{8,18,6,19,18,20},new int[]{-15,43,-16,28,-17,27,-14,17}); + states[43] = new State(new int[]{25,13,26,23,4,-28,10,-28,14,-28,22,-28}); + states[44] = new State(-3); + states[45] = new State(-10); + states[46] = new State(new int[]{8,18},new int[]{-6,47,-14,10}); + states[47] = new State(new int[]{16,48}); + states[48] = new State(new int[]{8,18,6,19,18,20},new int[]{-15,49,-16,28,-17,27,-14,17}); + states[49] = new State(new int[]{12,50,25,13,26,23}); + states[50] = new State(new int[]{8,18,3,4,5,31,11,35,13,40,15,46,17,53,20,58,23,65},new int[]{-5,51,-6,9,-14,10,-3,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[51] = new State(-29); + states[52] = new State(-11); + states[53] = new State(new int[]{18,54}); + states[54] = new State(new int[]{8,18,6,19,18,20},new int[]{-15,55,-16,28,-17,27,-14,17}); + states[55] = new State(new int[]{19,56,25,13,26,23}); + states[56] = new State(-30); + states[57] = new State(-12); + states[58] = new State(new int[]{8,18,6,19,18,20},new int[]{-15,59,-16,28,-17,27,-14,17}); + states[59] = new State(new int[]{21,60,25,13,26,23}); + states[60] = new State(new int[]{8,18,3,4,5,31,11,35,13,40,15,46,17,53,20,58,23,65},new int[]{-5,61,-6,9,-14,10,-3,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[61] = new State(new int[]{22,62,4,-32,10,-32,14,-32}); + states[62] = new State(new int[]{8,18,3,4,5,31,11,35,13,40,15,46,17,53,20,58,23,65},new int[]{-5,63,-6,9,-14,10,-3,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[63] = new State(-31); + states[64] = new State(-13); + states[65] = new State(new int[]{8,18},new int[]{-18,66,-14,69}); + states[66] = new State(new int[]{24,67,4,-33,10,-33,14,-33,22,-33}); + states[67] = new State(new int[]{8,18},new int[]{-14,68}); + states[68] = new State(-34); + states[69] = new State(-35); - rules[1] = new Rule(-2, new int[]{-1,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,11,-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[]{9}); - rules[9] = new Rule(-6, new int[]{-8,10,-9}); - rules[10] = new Rule(-9, new int[]{-8}); - rules[11] = new Rule(-9, new int[]{7}); - rules[12] = new Rule(-3, new int[]{4,-4,5}); - rules[13] = new Rule(-7, new int[]{6,-9,-5}); + rules[8] = new Rule(-5, new int[]{-8}); + rules[9] = new Rule(-5, new int[]{-9}); + rules[10] = new Rule(-5, new int[]{-10}); + rules[11] = new Rule(-5, new int[]{-11}); + rules[12] = new Rule(-5, new int[]{-12}); + rules[13] = new Rule(-5, new int[]{-13}); + rules[14] = new Rule(-14, new int[]{8}); + rules[15] = new Rule(-6, new int[]{-14,9,-15}); + rules[16] = new Rule(-15, new int[]{-16}); + rules[17] = new Rule(-15, new int[]{-15,25,-16}); + rules[18] = new Rule(-15, new int[]{-15,26,-16}); + rules[19] = new Rule(-16, new int[]{-17}); + rules[20] = new Rule(-16, new int[]{-16,27,-17}); + rules[21] = new Rule(-16, new int[]{-16,28,-17}); + rules[22] = new Rule(-17, new int[]{-14}); + rules[23] = new Rule(-17, new int[]{6}); + rules[24] = new Rule(-17, new int[]{18,-15,19}); + rules[25] = new Rule(-3, new int[]{3,-4,4}); + rules[26] = new Rule(-7, new int[]{5,-15,-5}); + rules[27] = new Rule(-8, new int[]{11,-15,12,-5}); + rules[28] = new Rule(-9, new int[]{13,-4,14,-15}); + rules[29] = new Rule(-10, new int[]{15,-6,16,-15,12,-5}); + rules[30] = new Rule(-11, new int[]{17,18,-15,19}); + rules[31] = new Rule(-12, new int[]{20,-15,21,-5,22,-5}); + rules[32] = new Rule(-12, new int[]{20,-15,21,-5}); + rules[33] = new Rule(-13, new int[]{23,-18}); + rules[34] = new Rule(-18, new int[]{-18,24,-14}); + rules[35] = new Rule(-18, new int[]{-14}); } protected override void Initialize() { @@ -108,17 +167,15 @@ public class Parser: ShiftReduceParser<int, LexLocation> protected override void DoAction(int action) { -#pragma warning disable 162, 1522 switch (action) { } -#pragma warning restore 162, 1522 } protected override string TerminalToString(int terminal) { - if (aliases != null && aliases.ContainsKey(terminal)) - return aliases[terminal]; + if (aliasses != null && aliasses.ContainsKey(terminal)) + return aliasses[terminal]; else if (((Tokens)terminal).ToString() != terminal.ToString(CultureInfo.InvariantCulture)) return ((Tokens)terminal).ToString(); else diff --git a/Module5/SimpleYacc.lst b/Module5/SimpleYacc.lst index 6a40f2d..0a56bd5 100644 --- a/Module5/SimpleYacc.lst +++ b/Module5/SimpleYacc.lst @@ -3,9 +3,9 @@ // GPPG error listing for yacc source file <SimpleYacc.y> // ========================================================================== // Version: 1.3.6 -// Machine: SSM -// DateTime: 17.08.2014 10:25:15 -// UserName: Станислав +// Machine: WIN-51KGPO1PTR9 +// DateTime: 28.11.2022 21:40:09 +// UserName: Администратор // ========================================================================== @@ -16,19 +16,17 @@ %output = SimpleYacc.cs -%using System.IO; - %namespace SimpleParser -%token BEGIN END CYCLE INUM RNUM ID ASSIGN SEMICOLON +%token BEGIN END CYCLE INUM RNUM ID ASSIGN SEMICOLON WHILE DO REPEAT UNTIL FOR TO WRITE %% -// 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} -// ------------------------------------------------------------------ +// Error: NonTerminal symbol "write" has no productions +// Warning: Terminating write fixes the following size-1 NonTerminal set + // {write} +// Error: There are 1 non-terminating NonTerminal Symbols + // {write} +// --------------------------------------------------------------------- progr : block ; @@ -39,7 +37,11 @@ stlist : statement statement: assign | block - | cycle + | cycle + | while + | repeat + | for + | write ; ident : ID @@ -55,10 +57,21 @@ expr : ident block : BEGIN stlist END ; -cycle : CYCLE expr st +cycle : CYCLE expr statement + ; + +while : WHILE expr DO statement ; + +repeat : REPEAT stlist UNTIL expr + ; + +for : FOR ID ASSIGN expr TO expr DO statement + ; + + + %% - // ========================================================================== diff --git a/Module5/SimpleYacc.y b/Module5/SimpleYacc.y index 9594732..ea88b7d 100644 --- a/Module5/SimpleYacc.y +++ b/Module5/SimpleYacc.y @@ -7,7 +7,7 @@ %namespace SimpleParser -%token BEGIN END CYCLE INUM RNUM ID ASSIGN SEMICOLON +%token BEGIN END CYCLE INUM RNUM ID ASSIGN SEMICOLON WHILE DO REPEAT UNTIL FOR TO WRITE LEFT_BRACKET RIGHT_BRACKET IF THEN ELSE VAR COMMA PLUS MINUS MULT DIV %% @@ -20,7 +20,13 @@ stlist : statement statement: assign | block - | cycle + | cycle + | while + | repeat + | for + | write + | if + | var ; ident : ID @@ -29,14 +35,51 @@ ident : ID assign : ident ASSIGN expr ; -expr : ident - | INUM - ; +// дополнение грамматики +expr : t + | expr PLUS t + | expr MINUS t + ; + +t : f + | t MULT f + | t DIV f + ; + +f : ident + | INUM + | LEFT_BRACKET expr RIGHT_BRACKET + ; +// дополнение грамматики + block : BEGIN stlist END ; cycle : CYCLE expr statement ; - + +while : WHILE expr DO statement + ; + +repeat : REPEAT stlist UNTIL expr + ; + +for : FOR assign TO expr DO statement + ; + +write : WRITE LEFT_BRACKET expr RIGHT_BRACKET + ; + +if : IF expr THEN statement ELSE statement + | IF expr THEN statement + ; + +var : VAR id_list + ; + +id_list : id_list COMMA ident + | ident + ; + %% diff --git a/Module5/packages.config b/Module5/packages.config new file mode 100644 index 0000000..e68db37 --- /dev/null +++ b/Module5/packages.config @@ -0,0 +1,6 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> +</packages> \ No newline at end of file diff --git a/Module6/ParserAST.csproj b/Module6/ParserAST.csproj index b6c10a7..b5dfa80 100644 --- a/Module6/ParserAST.csproj +++ b/Module6/ParserAST.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">x86</Platform> @@ -14,6 +16,8 @@ <TargetFrameworkProfile> </TargetFrameworkProfile> <FileAlignment>512</FileAlignment> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PlatformTarget>x86</PlatformTarget> @@ -64,6 +68,9 @@ <HintPath>..\packages\Newtonsoft.Json.11.0.2\lib\net35\Newtonsoft.Json.dll</HintPath> <Private>True</Private> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> @@ -90,6 +97,13 @@ <Content Include="SimpleYacc.y" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> <!-- 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"> diff --git a/Module6/ProgramTree.cs b/Module6/ProgramTree.cs index ade12f7..2def4a9 100644 --- a/Module6/ProgramTree.cs +++ b/Module6/ProgramTree.cs @@ -4,6 +4,8 @@ namespace ProgramTree { public enum AssignType { Assign, AssignPlus, AssignMinus, AssignMult, AssignDivide }; + public enum BinOpType { ADD, SUB, MUL, DIV }; + public class Node // базовый класс для всех узлов { } @@ -65,4 +67,94 @@ namespace ProgramTree } } + public class WhileNode : StatementNode + { + public ExprNode Expr { get; set; } + public StatementNode Stat { get; set; } + public WhileNode(ExprNode expr, StatementNode stat) + { + Expr = expr; + Stat = stat; + } + } + + public class RepeatNode : StatementNode + { + public ExprNode Expr { get; set; } + public BlockNode StList { get; set; } + public RepeatNode(BlockNode stlist, ExprNode expr) + { + Expr = expr; + StList = stlist; + } + } + + public class ForNode : StatementNode + { + public AssignNode Assign { get; set; } + public ExprNode Expr { get; set; } + public StatementNode Statement { get; set; } + public ForNode(AssignNode assi, ExprNode expr, StatementNode st) + { + Assign = assi; + Expr = expr; + Statement = st; + } + } + + public class WriteNode : StatementNode + { + public ExprNode Expr { get; set; } + public WriteNode(ExprNode expr) + { + Expr = expr; + } + } + + public class IfNode : StatementNode + { + public ExprNode Expr { get; set; } + public StatementNode IfStat { get; set; } + public StatementNode ElseStat { get; set; } + public IfNode(ExprNode expr, StatementNode ifStat, StatementNode elseStat) + { + Expr = expr; + IfStat = ifStat; + ElseStat = elseStat; + } + + public IfNode(ExprNode expr, StatementNode ifStat) + { + Expr = expr; + IfStat = ifStat; + ElseStat = null; + } + } + + public class VarNode : StatementNode + { + public List<IdNode> IDList = new List<IdNode>(); + public VarNode(IdNode id) + { + Add(id); + } + public void Add(IdNode id) + { + IDList.Add(id); + } + } + + public class BinNode : ExprNode + { + public ExprNode Left { get; set; } + public ExprNode Right { get; set; } + public BinOpType Operation { get; set; } + public BinNode(ExprNode left, ExprNode right, BinOpType operation) + { + Left = left; + Right = right; + Operation = operation; + } + } + } \ No newline at end of file diff --git a/Module6/SimpleLex.cs b/Module6/SimpleLex.cs index c518c8b..06b6f63 100644 --- a/Module6/SimpleLex.cs +++ b/Module6/SimpleLex.cs @@ -1,14 +1,10 @@ // // This CSharp output file generated by Gardens Point LEX -// Gardens Point LEX (GPLEX) is Copyright (c) John Gough, QUT 2006-2014. -// Output produced by GPLEX is the property of the user. -// See accompanying file GPLEXcopyright.rtf. -// -// GPLEX Version: 1.2.2 -// Machine: MAINHOMEPC2 -// DateTime: 30.09.2018 18:14:30 -// UserName: someone -// GPLEX input file <SimpleLex.lex - 24.09.2018 23:47:03> +// Version: 1.1.3.301 +// Machine: WIN-51KGPO1PTR9 +// DateTime: 29.11.2022 12:28:16 +// UserName: ????????????? +// GPLEX input file <SimpleLex.lex> // GPLEX frame file <embedded resource> // // Option settings: unicode, parser, minimize @@ -17,8 +13,8 @@ // // -// Revised backup code -// Version 1.2.1 of 24-June-2013 +// Experimental embedded frame +// Version 1.1.3 of 18-April-2010 // // #define BACKUP @@ -127,8 +123,8 @@ namespace SimpleScanner enum Result {accept, noMatch, contextFound}; - const int maxAccept = 7; - const int initial = 8; + const int maxAccept = 14; + const int initial = 15; const int eofNum = 0; const int goStart = -1; const int INITIAL = 0; @@ -165,24 +161,24 @@ namespace SimpleScanner } }; - static int[] startState = new int[] {8, 0}; + static int[] startState = new int[] {15, 0}; #region CompressedCharacterMap // - // There are 8 equivalence classes + // 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' */ 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, +/* '\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, 7, 8, 13, 10, 9, 11, 2, 12, +/* '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) @@ -190,22 +186,29 @@ namespace SimpleScanner if (code < 123) // '\0' <= code <= 'z' return mapC0[code - 0]; else // '{' <= code <= '\U0010FFFF' - return (sbyte)7; + return (sbyte)14; } #endregion - static Table[] NxS = new Table[10] { + static Table[] NxS = new Table[17] { /* NxS[ 0] */ new Table(0, 0, 0, null), -/* NxS[ 1] */ new Table(1, 2, -1, new sbyte[] {1, 9}), +/* NxS[ 1] */ new Table(1, 2, -1, new sbyte[] {1, 16}), /* 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[ 4] */ new Table(5, 1, -1, new sbyte[] {13}), /* 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}), +/* NxS[ 7] */ new Table(0, 0, -1, null), +/* NxS[ 8] */ new Table(0, 0, -1, null), +/* 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(1, 1, -1, new sbyte[] {14}), +/* NxS[ 15] */ new Table(1, 14, -1, new sbyte[] {1, 2, 3, 4, 2, 5, + 6, 7, 8, 9, 10, 11, 12, 2}), +/* NxS[ 16] */ new Table(1, 1, -1, new sbyte[] {14}), }; int NextState() { @@ -215,7 +218,7 @@ int NextState() { unchecked { int rslt; int idx = MapC(code) - NxS[state].min; - if (idx < 0) idx += 8; + if (idx < 0) idx += 15; if ((uint)idx >= (uint)NxS[state].rng) rslt = NxS[state].dflt; else rslt = NxS[state].nxt[idx]; return rslt; @@ -295,7 +298,8 @@ int NextState() { public Scanner(Stream file, string codepage) { SetSource(file, CodePageHandling.GetCodePage(codepage)); - } + } + #endif // !NOFILES public Scanner() { } @@ -323,7 +327,7 @@ int NextState() { if (next < 0xDC00 || next > 0xDFFF) code = ScanBuff.UnicodeReplacementChar; else - code = (0x10000 + ((code & 0x3FF) << 10) + (next & 0x3FF)); + code = (0x10000 + (code & 0x3FF << 10) + (next & 0x3FF)); } #endif cCol++; @@ -376,7 +380,9 @@ int NextState() { GetCode(); } +#if !NOFILES // ================ LineBuffer Initialization =================== + /// <summary> /// Create and initialize a LineBuff buffer object for this scanner /// </summary> @@ -390,7 +396,6 @@ int NextState() { GetCode(); } -#if !NOFILES // =============== StreamBuffer Initialization ================== /// <summary> @@ -492,12 +497,6 @@ int NextState() { } } - /// <summary> - /// Discards all but the first "n" codepoints in the recognized pattern. - /// Resets the buffer position so that only n codepoints have been consumed; - /// yytext is also re-evaluated. - /// </summary> - /// <param name="n">The number of codepoints to consume</param> [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] void yyless(int n) { @@ -517,10 +516,6 @@ int NextState() { // but it does not seem possible to re-establish // the correct column counts except by going forward. // - /// <summary> - /// Removes the last "n" code points from the pattern. - /// </summary> - /// <param name="n">The number to remove</param> [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] void _yytrunc(int n) { yyless(yyleng - n); } @@ -533,23 +528,18 @@ int NextState() { // can't use (tokEPos - tokPos) because of the // possibility of surrogate pairs in the token. // - /// <summary> - /// The length of the pattern in codepoints (not the same as - /// string-length if the pattern contains any surrogate pairs). - /// </summary> [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 -#if BYTEMODE - return tokEPos - tokPos; -#else - { + else { int ch; int count = 0; int save = buffer.Pos; @@ -558,7 +548,7 @@ int NextState() { ch = buffer.Read(); if (!char.IsHighSurrogate((char)ch)) count++; } while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile); - buffer.Pos = save; + buffer.Pos = save; return count; } #endif // BYTEMODE @@ -583,56 +573,65 @@ int NextState() { // ============== The main tokenizer code ================= - int Scan() { + int Scan() + { try { - for (; ; ) { - int next; // next state to enter + for (; ; ) + { + int next; // next state to enter +#if BACKUP + Result rslt = Result.noMatch; +#endif // BACKUP #if LEFTANCHORS - for (;;) { + 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... + if ((next = NextState()) != goStart) + break; // LOOP EXIT HERE... GetCode(); } #else // !LEFTANCHORS state = currentStart; - while ((next = NextState()) == goStart) { + 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(); + GetCode(); + + while ((next = NextState()) > eofNum) // Exit for goStart AND for eofNum #if BACKUP - bool contextSaved = false; - while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum - if (state <= maxAccept && next > maxAccept) { // need to prepare backup data - // Store data for the *latest* accept state that was found. - SaveStateAndPos( ref ctx ); - contextSaved = true; + 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; } - state = next; - GetCode(); - } - if (state > maxAccept && contextSaved) - RestoreStateAndPos( ref ctx ); -#else // BACKUP - while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum - state = next; - GetCode(); - } + else #endif // BACKUP - if (state <= maxAccept) { + { + state = next; + GetCode(); + } + if (state <= maxAccept) + { MarkEnd(); #region ActionSwitch -#pragma warning disable 162, 1522 +#pragma warning disable 162 switch (state) { case eofNum: @@ -657,16 +656,37 @@ int res = ScannerHelper.GetIDToken(yytext); return (int)Tokens.SEMICOLON; break; case 6: -return (int)Tokens.ASSIGN; +return (int)Tokens.LBRACKET; break; case 7: +return (int)Tokens.RBRACKET; + break; + case 8: +return (int)Tokens.COMMA; + break; + case 9: +return (int)Tokens.ADD; + break; + case 10: +return (int)Tokens.SUB; + break; + case 11: +return (int)Tokens.DIV; + break; + case 12: +return (int)Tokens.MUL; + break; + case 13: +return (int)Tokens.ASSIGN; + break; + case 14: yylval.dVal = double.Parse(yytext); return (int)Tokens.RNUM; break; default: break; } -#pragma warning restore 162, 1522 +#pragma warning restore 162 #endregion } } @@ -679,7 +699,29 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); } #if BACKUP - void SaveStateAndPos(ref Context ctx) { + 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; @@ -688,7 +730,8 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); ctx.cChr = code; } - void RestoreStateAndPos(ref Context ctx) { + void RestoreStateAndPos(ref Context ctx) + { buffer.Pos = ctx.bPos; readPos = ctx.rPos; cCol = ctx.cCol; @@ -696,7 +739,8 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); state = ctx.state; code = ctx.cChr; } -#endif // BACKUP + +#endif // BACKUP // ============= End of the tokenizer code ================ @@ -728,16 +772,16 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); #region UserCodeSection -public override void yyerror(string format, params object[] args) // îáðà áîòêà ñèГГІГ ГЄГ±ГЁГ·ГҐГ±ГЄГЁГµ îøèáîê +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)); + 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); + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); throw new LexException(errorMsg); } @@ -751,6 +795,18 @@ class ScannerHelper keywords.Add("begin",(int)Tokens.BEGIN); keywords.Add("end",(int)Tokens.END); keywords.Add("cycle",(int)Tokens.CYCLE); + keywords.Add("while",(int)Tokens.WHILE); + keywords.Add("do",(int)Tokens.DO); + keywords.Add("repeat",(int)Tokens.REPEAT); + keywords.Add("until",(int)Tokens.UNTIL); + keywords.Add("for",(int)Tokens.FOR); + keywords.Add("to",(int)Tokens.TO); + keywords.Add("write",(int)Tokens.WRITE); + keywords.Add("if",(int)Tokens.IF); + keywords.Add("then",(int)Tokens.THEN); + keywords.Add("else",(int)Tokens.ELSE); + keywords.Add("var",(int)Tokens.VAR); + } public static int GetIDToken(string s) { @@ -811,7 +867,6 @@ class ScannerHelper return new LineBuffer(source); } -#if (!NOFILES) public static ScanBuff GetBuffer(Stream source) { return new BuildBuffer(source); @@ -822,8 +877,7 @@ class ScannerHelper { return new BuildBuffer(source, fallbackCodePage); } -#endif // !BYTEMODE -#endif // !NOFILES +#endif } #region Buffer classes @@ -946,7 +1000,7 @@ class ScannerHelper { ix = lstart = 0; } - while (ix < numLines) + for (; ; ) { int len = line[ix].Length + 1; if (pos < lstart + len) break; @@ -1004,8 +1058,7 @@ class ScannerHelper { cPos = value; findIndex(cPos, out cLine, out curLineStart); - // cLine should be the *next* line after curLine. - curLine = (cLine < numLines ? line[cLine++] : ""); + curLine = line[cLine]; curLineEnd = curLineStart + curLine.Length; } } @@ -1013,7 +1066,7 @@ class ScannerHelper public override string ToString() { return "LineBuffer"; } } -#if (!NOFILES) + // ============================================================== // ===== class BuildBuff : for unicode text files ======== // ============================================================== @@ -1254,13 +1307,12 @@ class ScannerHelper } #endif // !BYTEMODE } -#endif // !NOFILES #endregion Buffer classes // ============================================================== // ============ class CodePageHandling ============= // ============================================================== -#if (!NOFILES) + public static class CodePageHandling { public static int GetCodePage(string option) @@ -1471,7 +1523,6 @@ class ScannerHelper #endif // !BYTEMODE #endregion -#endif // !NOFILES // End of code copied from embedded resource diff --git a/Module6/SimpleLex.lex b/Module6/SimpleLex.lex index 20b364f..ec6e6f5 100644 --- a/Module6/SimpleLex.lex +++ b/Module6/SimpleLex.lex @@ -32,6 +32,15 @@ ID {Alpha}{AlphaDigit}* ":=" { return (int)Tokens.ASSIGN; } ";" { return (int)Tokens.SEMICOLON; } +"(" { return (int)Tokens.LBRACKET; } +")" { return (int)Tokens.RBRACKET; } +"," { return (int)Tokens.COMMA; } +"+" { return (int)Tokens.ADD; } +"-" { return (int)Tokens.SUB; } +"/" { return (int)Tokens.DIV; } +"*" { return (int)Tokens.MUL; } + + [^ \r\n] { LexError(); @@ -66,6 +75,18 @@ class ScannerHelper keywords.Add("begin",(int)Tokens.BEGIN); keywords.Add("end",(int)Tokens.END); keywords.Add("cycle",(int)Tokens.CYCLE); + keywords.Add("while",(int)Tokens.WHILE); + keywords.Add("do",(int)Tokens.DO); + keywords.Add("repeat",(int)Tokens.REPEAT); + keywords.Add("until",(int)Tokens.UNTIL); + keywords.Add("for",(int)Tokens.FOR); + keywords.Add("to",(int)Tokens.TO); + keywords.Add("write",(int)Tokens.WRITE); + keywords.Add("if",(int)Tokens.IF); + keywords.Add("then",(int)Tokens.THEN); + keywords.Add("else",(int)Tokens.ELSE); + keywords.Add("var",(int)Tokens.VAR); + } public static int GetIDToken(string s) { diff --git a/Module6/SimpleYacc.cs b/Module6/SimpleYacc.cs index b13b1e9..be9e542 100644 --- a/Module6/SimpleYacc.cs +++ b/Module6/SimpleYacc.cs @@ -1,18 +1,17 @@ // This code was generated by the Gardens Point Parser Generator -// Copyright (c) Wayne Kelly, John Gough, QUT 2005-2014 +// Copyright (c) Wayne Kelly, QUT 2005-2010 // (see accompanying GPPGcopyright.rtf) -// GPPG version 1.5.2 -// Machine: MAINHOMEPC2 -// DateTime: 30.09.2018 18:14:41 -// UserName: someone -// Input file <SimpleYacc.y - 24.09.2018 23:47:03> +// GPPG version 1.3.6 +// Machine: WIN-51KGPO1PTR9 +// DateTime: 29.11.2022 12:28:17 +// UserName: ????????????? +// Input file <SimpleYacc.y> // options: no-lines gplex using System; using System.Collections.Generic; -using System.CodeDom.Compiler; using System.Globalization; using System.Text; using QUT.Gppg; @@ -20,8 +19,12 @@ using ProgramTree; namespace SimpleParser { -public enum Tokens {error=2,EOF=3,BEGIN=4,END=5,CYCLE=6, - ASSIGN=7,SEMICOLON=8,INUM=9,RNUM=10,ID=11}; +public enum Tokens { + error=1,EOF=2,BEGIN=3,END=4,CYCLE=5,ASSIGN=6, + SEMICOLON=7,WHILE=8,DO=9,REPEAT=10,UNTIL=11,FOR=12, + TO=13,WRITE=14,LBRACKET=15,RBRACKET=16,IF=17,THEN=18, + ELSE=19,VAR=20,COMMA=21,ADD=22,SUB=23,MUL=24, + DIV=25,INUM=26,RNUM=27,ID=28}; public struct ValueType { @@ -34,81 +37,134 @@ public struct ValueType public BlockNode blVal; } // Abstract base class for GPLEX scanners -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] 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; } } -// Utility class for encapsulating token information -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] -public class ScanObj { - public int token; - public ValueType yylval; - public LexLocation yylloc; - public ScanObj( int t, ValueType val, LexLocation loc ) { - this.token = t; this.yylval = val; this.yylloc = loc; - } -} - -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] public class Parser: ShiftReduceParser<ValueType, LexLocation> { - // Verbatim content from SimpleYacc.y - 24.09.2018 23:47:03 -// ГќГІГЁ îáúÿâëåГГЁГї äîáà âëÿþòñÿ Гў êëà ññ GPPGParser, ïðåäñòà âëÿþùèé ñîáîé ïà ðñåð, ГЈГҐГåðèðóåìûé ñèñòåìîé gppg - public BlockNode root; // ÊîðГåâîé óçåë Г±ГЁГòà êñè÷åñêîãî äåðåâà + // Verbatim content from SimpleYacc.y +// Эти объявления добавляются в класс GPPGParser, представляющий собой парсер, генерируемый системой gppg + public BlockNode root; // Корневой узел синтаксического дерева public Parser(AbstractScanner<ValueType, LexLocation> scanner) : base(scanner) { } - // End verbatim content from SimpleYacc.y - 24.09.2018 23:47:03 + // End verbatim content from SimpleYacc.y #pragma warning disable 649 - private static Dictionary<int, string> aliases; + 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 Rule[] rules = new Rule[35]; + private static State[] states = new State[69]; private static string[] nonTerms = new string[] { - "expr", "ident", "assign", "statement", "cycle", "stlist", "block", "progr", - "$accept", }; + "expr", "ident", "T", "F", "assign", "statement", "cycle", "while", "repeat", + "for", "write", "if", "var", "stlist", "block", "progr", "$accept", }; static Parser() { - states[0] = new State(new int[]{4,4},new int[]{-8,1,-7,3}); - states[1] = new State(new int[]{3,2}); + states[0] = new State(new int[]{3,4},new int[]{-16,1,-15,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[]{11,14,4,4,6,18},new int[]{-6,5,-4,21,-3,9,-2,10,-7,16,-5,17}); - states[5] = new State(new int[]{5,6,8,7}); - states[6] = new State(-12); - states[7] = new State(new int[]{11,14,4,4,6,18},new int[]{-4,8,-3,9,-2,10,-7,16,-5,17}); + states[4] = new State(new int[]{28,18,3,4,5,31,8,35,10,40,12,46,14,53,17,58,20,67},new int[]{-14,5,-6,44,-5,9,-2,10,-15,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[5] = new State(new int[]{4,6,7,7}); + states[6] = new State(-25); + states[7] = new State(new int[]{28,18,3,4,5,31,8,35,10,40,12,46,14,53,17,58,20,67},new int[]{-6,8,-5,9,-2,10,-15,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); states[8] = new State(-4); states[9] = new State(-5); - states[10] = new State(new int[]{7,11}); - states[11] = new State(new int[]{11,14,9,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[]{11,14,9,15},new int[]{-1,19,-2,13}); - states[19] = new State(new int[]{11,14,4,4,6,18},new int[]{-4,20,-3,9,-2,10,-7,16,-5,17}); - states[20] = new State(-13); - states[21] = new State(-3); - - for (int sNo = 0; sNo < states.Length; sNo++) states[sNo].number = sNo; + states[10] = new State(new int[]{6,11}); + states[11] = new State(new int[]{28,18,26,19,15,20},new int[]{-1,12,-3,28,-4,27,-2,17}); + states[12] = new State(new int[]{22,13,23,23,4,-15,7,-15,11,-15,19,-15,13,-15}); + states[13] = new State(new int[]{28,18,26,19,15,20},new int[]{-3,14,-4,27,-2,17}); + states[14] = new State(new int[]{24,15,25,25,22,-17,23,-17,4,-17,7,-17,11,-17,19,-17,13,-17,16,-17,28,-17,3,-17,5,-17,8,-17,10,-17,12,-17,14,-17,17,-17,20,-17,9,-17,18,-17}); + states[15] = new State(new int[]{28,18,26,19,15,20},new int[]{-4,16,-2,17}); + states[16] = new State(-20); + states[17] = new State(-22); + states[18] = new State(-14); + states[19] = new State(-23); + states[20] = new State(new int[]{28,18,26,19,15,20},new int[]{-1,21,-3,28,-4,27,-2,17}); + states[21] = new State(new int[]{16,22,22,13,23,23}); + states[22] = new State(-24); + states[23] = new State(new int[]{28,18,26,19,15,20},new int[]{-3,24,-4,27,-2,17}); + states[24] = new State(new int[]{24,15,25,25,22,-18,23,-18,4,-18,7,-18,11,-18,19,-18,13,-18,16,-18,28,-18,3,-18,5,-18,8,-18,10,-18,12,-18,14,-18,17,-18,20,-18,9,-18,18,-18}); + states[25] = new State(new int[]{28,18,26,19,15,20},new int[]{-4,26,-2,17}); + states[26] = new State(-21); + states[27] = new State(-19); + states[28] = new State(new int[]{24,15,25,25,22,-16,23,-16,4,-16,7,-16,11,-16,19,-16,13,-16,16,-16,28,-16,3,-16,5,-16,8,-16,10,-16,12,-16,14,-16,17,-16,20,-16,9,-16,18,-16}); + states[29] = new State(-6); + states[30] = new State(-7); + states[31] = new State(new int[]{28,18,26,19,15,20},new int[]{-1,32,-3,28,-4,27,-2,17}); + states[32] = new State(new int[]{22,13,23,23,28,18,3,4,5,31,8,35,10,40,12,46,14,53,17,58,20,67},new int[]{-6,33,-5,9,-2,10,-15,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[33] = new State(-26); + states[34] = new State(-8); + states[35] = new State(new int[]{28,18,26,19,15,20},new int[]{-1,36,-3,28,-4,27,-2,17}); + states[36] = new State(new int[]{9,37,22,13,23,23}); + states[37] = new State(new int[]{28,18,3,4,5,31,8,35,10,40,12,46,14,53,17,58,20,67},new int[]{-6,38,-5,9,-2,10,-15,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[38] = new State(-27); + states[39] = new State(-9); + states[40] = new State(new int[]{28,18,3,4,5,31,8,35,10,40,12,46,14,53,17,58,20,67},new int[]{-14,41,-6,44,-5,9,-2,10,-15,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[41] = new State(new int[]{11,42,7,7}); + states[42] = new State(new int[]{28,18,26,19,15,20},new int[]{-1,43,-3,28,-4,27,-2,17}); + states[43] = new State(new int[]{22,13,23,23,4,-28,7,-28,11,-28,19,-28}); + states[44] = new State(-3); + states[45] = new State(-10); + states[46] = new State(new int[]{28,18},new int[]{-5,47,-2,10}); + states[47] = new State(new int[]{13,48}); + states[48] = new State(new int[]{28,18,26,19,15,20},new int[]{-1,49,-3,28,-4,27,-2,17}); + states[49] = new State(new int[]{9,50,22,13,23,23}); + states[50] = new State(new int[]{28,18,3,4,5,31,8,35,10,40,12,46,14,53,17,58,20,67},new int[]{-6,51,-5,9,-2,10,-15,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[51] = new State(-29); + states[52] = new State(-11); + states[53] = new State(new int[]{15,54}); + states[54] = new State(new int[]{28,18,26,19,15,20},new int[]{-1,55,-3,28,-4,27,-2,17}); + states[55] = new State(new int[]{16,56,22,13,23,23}); + states[56] = new State(-30); + states[57] = new State(-12); + states[58] = new State(new int[]{28,18,26,19,15,20},new int[]{-1,59,-3,28,-4,27,-2,17}); + states[59] = new State(new int[]{18,60,22,13,23,23}); + states[60] = new State(new int[]{28,18,3,4,5,31,8,35,10,40,12,46,14,53,17,58,20,67},new int[]{-6,61,-5,9,-2,10,-15,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[61] = new State(new int[]{19,62,4,-31,7,-31,11,-31}); + states[62] = new State(new int[]{28,18,3,4,5,31,8,35,10,40,12,46,14,53,17,58,20,67},new int[]{-6,63,-5,9,-2,10,-15,29,-7,30,-8,34,-9,39,-10,45,-11,52,-12,57,-13,64}); + states[63] = new State(-32); + states[64] = new State(new int[]{21,65,4,-13,7,-13,11,-13,19,-13}); + states[65] = new State(new int[]{28,18},new int[]{-2,66}); + states[66] = new State(-34); + states[67] = new State(new int[]{28,18},new int[]{-2,68}); + states[68] = new State(-33); - rules[1] = new Rule(-9, new int[]{-8,3}); - rules[2] = new Rule(-8, new int[]{-7}); - rules[3] = new Rule(-6, new int[]{-4}); - rules[4] = new Rule(-6, new int[]{-6,8,-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[]{11}); - rules[9] = new Rule(-3, new int[]{-2,7,-1}); - rules[10] = new Rule(-1, new int[]{-2}); - rules[11] = new Rule(-1, new int[]{9}); - rules[12] = new Rule(-7, new int[]{4,-6,5}); - rules[13] = new Rule(-5, new int[]{6,-1,-4}); + rules[1] = new Rule(-17, new int[]{-16,2}); + rules[2] = new Rule(-16, new int[]{-15}); + rules[3] = new Rule(-14, new int[]{-6}); + rules[4] = new Rule(-14, new int[]{-14,7,-6}); + rules[5] = new Rule(-6, new int[]{-5}); + rules[6] = new Rule(-6, new int[]{-15}); + rules[7] = new Rule(-6, new int[]{-7}); + rules[8] = new Rule(-6, new int[]{-8}); + rules[9] = new Rule(-6, new int[]{-9}); + rules[10] = new Rule(-6, new int[]{-10}); + rules[11] = new Rule(-6, new int[]{-11}); + rules[12] = new Rule(-6, new int[]{-12}); + rules[13] = new Rule(-6, new int[]{-13}); + rules[14] = new Rule(-2, new int[]{28}); + rules[15] = new Rule(-5, new int[]{-2,6,-1}); + rules[16] = new Rule(-1, new int[]{-3}); + rules[17] = new Rule(-1, new int[]{-1,22,-3}); + rules[18] = new Rule(-1, new int[]{-1,23,-3}); + rules[19] = new Rule(-3, new int[]{-4}); + rules[20] = new Rule(-3, new int[]{-3,24,-4}); + rules[21] = new Rule(-3, new int[]{-3,25,-4}); + rules[22] = new Rule(-4, new int[]{-2}); + rules[23] = new Rule(-4, new int[]{26}); + rules[24] = new Rule(-4, new int[]{15,-1,16}); + rules[25] = new Rule(-15, new int[]{3,-14,4}); + rules[26] = new Rule(-7, new int[]{5,-1,-6}); + rules[27] = new Rule(-8, new int[]{8,-1,9,-6}); + rules[28] = new Rule(-9, new int[]{10,-14,11,-1}); + rules[29] = new Rule(-10, new int[]{12,-5,13,-1,9,-6}); + rules[30] = new Rule(-11, new int[]{14,15,-1,16}); + rules[31] = new Rule(-12, new int[]{17,-1,18,-6}); + rules[32] = new Rule(-12, new int[]{17,-1,18,-6,19,-6}); + rules[33] = new Rule(-13, new int[]{20,-2}); + rules[34] = new Rule(-13, new int[]{-13,21,-2}); } protected override void Initialize() { @@ -120,7 +176,6 @@ public class Parser: ShiftReduceParser<ValueType, LexLocation> protected override void DoAction(int action) { -#pragma warning disable 162, 1522 switch (action) { case 2: // progr -> block @@ -146,32 +201,91 @@ public class Parser: ShiftReduceParser<ValueType, LexLocation> case 7: // statement -> cycle { CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } break; - case 8: // ident -> ID + case 8: // statement -> while +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 9: // statement -> repeat +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 10: // statement -> for +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 11: // statement -> write +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 12: // statement -> if +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 13: // statement -> var +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 14: // ident -> ID { CurrentSemanticValue.eVal = new IdNode(ValueStack[ValueStack.Depth-1].sVal); } break; - case 9: // assign -> ident, ASSIGN, expr + case 15: // 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 + case 17: // expr -> expr, ADD, T +{CurrentSemanticValue.eVal = new BinNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,BinOpType.ADD);} + break; + case 18: // expr -> expr, SUB, T +{CurrentSemanticValue.eVal = new BinNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,BinOpType.SUB);} + break; + case 20: // T -> T, MUL, F +{CurrentSemanticValue.eVal = new BinNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,BinOpType.MUL);} + break; + case 21: // T -> T, DIV, F +{CurrentSemanticValue.eVal = new BinNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,BinOpType.DIV);} + break; + case 22: // F -> ident { CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal as IdNode; } break; - case 11: // expr -> INUM + case 23: // F -> INUM { CurrentSemanticValue.eVal = new IntNumNode(ValueStack[ValueStack.Depth-1].iVal); } break; - case 12: // block -> BEGIN, stlist, END + case 24: // F -> LBRACKET, expr, RBRACKET +{ CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-2].eVal; } + break; + case 25: // block -> BEGIN, stlist, END { CurrentSemanticValue.blVal = ValueStack[ValueStack.Depth-2].blVal; } break; - case 13: // cycle -> CYCLE, expr, statement + case 26: // cycle -> CYCLE, expr, statement { CurrentSemanticValue.stVal = new CycleNode(ValueStack[ValueStack.Depth-2].eVal, ValueStack[ValueStack.Depth-1].stVal); } break; + case 27: // while -> WHILE, expr, DO, statement +{ CurrentSemanticValue.stVal = new WhileNode(ValueStack[ValueStack.Depth-3].eVal, ValueStack[ValueStack.Depth-1].stVal);} + break; + case 28: // repeat -> REPEAT, stlist, UNTIL, expr +{ CurrentSemanticValue.stVal = new RepeatNode(ValueStack[ValueStack.Depth-3].blVal, ValueStack[ValueStack.Depth-1].eVal);} + break; + case 29: // for -> FOR, assign, TO, expr, DO, statement +{ CurrentSemanticValue.stVal = new ForNode(ValueStack[ValueStack.Depth-5].stVal as AssignNode, ValueStack[ValueStack.Depth-3].eVal, ValueStack[ValueStack.Depth-1].stVal); } + break; + case 30: // write -> WRITE, LBRACKET, expr, RBRACKET +{ CurrentSemanticValue.stVal = new WriteNode(ValueStack[ValueStack.Depth-2].eVal);} + break; + case 31: // if -> IF, expr, THEN, statement +{ CurrentSemanticValue.stVal = new IfNode(ValueStack[ValueStack.Depth-3].eVal, ValueStack[ValueStack.Depth-1].stVal);} + break; + case 32: // if -> IF, expr, THEN, statement, ELSE, statement +{ CurrentSemanticValue.stVal = new IfNode(ValueStack[ValueStack.Depth-5].eVal, ValueStack[ValueStack.Depth-3].stVal, ValueStack[ValueStack.Depth-1].stVal); } + break; + case 33: // var -> VAR, ident +{ CurrentSemanticValue.stVal = new VarNode(ValueStack[ValueStack.Depth-1].eVal as IdNode);} + break; + case 34: // var -> var, COMMA, ident +{ + (ValueStack[ValueStack.Depth-3].stVal as VarNode).Add(ValueStack[ValueStack.Depth-1].eVal as IdNode); + CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-3].stVal; + } + break; } -#pragma warning restore 162, 1522 } protected override string TerminalToString(int terminal) { - if (aliases != null && aliases.ContainsKey(terminal)) - return aliases[terminal]; + if (aliasses != null && aliasses.ContainsKey(terminal)) + return aliasses[terminal]; else if (((Tokens)terminal).ToString() != terminal.ToString(CultureInfo.InvariantCulture)) return ((Tokens)terminal).ToString(); else diff --git a/Module6/SimpleYacc.y b/Module6/SimpleYacc.y index b9899b4..c8c22f0 100644 --- a/Module6/SimpleYacc.y +++ b/Module6/SimpleYacc.y @@ -20,13 +20,13 @@ %namespace SimpleParser -%token BEGIN END CYCLE ASSIGN SEMICOLON +%token BEGIN END CYCLE ASSIGN SEMICOLON WHILE DO REPEAT UNTIL FOR TO WRITE LBRACKET RBRACKET IF THEN ELSE VAR COMMA ADD SUB MUL DIV %token <iVal> INUM %token <dVal> RNUM %token <sVal> ID -%type <eVal> expr ident -%type <stVal> assign statement cycle +%type <eVal> expr ident T F +%type <stVal> assign statement cycle while repeat for write if var %type <blVal> stlist block %% @@ -48,6 +48,12 @@ stlist : statement statement: assign { $$ = $1; } | block { $$ = $1; } | cycle { $$ = $1; } + | while { $$ = $1; } + | repeat { $$ = $1; } + | for { $$ = $1; } + | write { $$ = $1; } + | if { $$ = $1; } + | var { $$ = $1; } ; ident : ID { $$ = new IdNode($1); } @@ -56,15 +62,53 @@ ident : ID { $$ = new IdNode($1); } assign : ident ASSIGN expr { $$ = new AssignNode($1 as IdNode, $3); } ; -expr : ident { $$ = $1 as IdNode; } +expr : T + | expr ADD T {$$ = new BinNode($1,$3,BinOpType.ADD);} + | expr SUB T {$$ = new BinNode($1,$3,BinOpType.SUB);} + ; + +T : F + | T MUL F {$$ = new BinNode($1,$3,BinOpType.MUL);} + | T DIV F {$$ = new BinNode($1,$3,BinOpType.DIV);} + ; + +F : ident { $$ = $1 as IdNode; } | INUM { $$ = new IntNumNode($1); } + | LBRACKET expr RBRACKET { $$ = $2; } ; + + + block : BEGIN stlist END { $$ = $2; } ; cycle : CYCLE expr statement { $$ = new CycleNode($2, $3); } ; - + +while : WHILE expr DO statement{ $$ = new WhileNode($2, $4);} + ; + +repeat : REPEAT stlist UNTIL expr { $$ = new RepeatNode($2, $4);} + ; + +for : FOR assign TO expr DO statement { $$ = new ForNode($2 as AssignNode, $4, $6); } + ; + +write : WRITE LBRACKET expr RBRACKET { $$ = new WriteNode($3);} + ; + +if : IF expr THEN statement { $$ = new IfNode($2, $4);} + | IF expr THEN statement ELSE statement { $$ = new IfNode($2, $4, $6); } + ; + +var : VAR ident { $$ = new VarNode($2 as IdNode);} + | var COMMA ident + { + ($1 as VarNode).Add($3 as IdNode); + $$ = $1; + } + ; + %% diff --git a/Module6/generateParserScanner.bat b/Module6/generateParserScanner.bat index 7ca5476..06c5897 100644 --- a/Module6/generateParserScanner.bat +++ b/Module6/generateParserScanner.bat @@ -1,3 +1,4 @@ cls gplex.exe /unicode SimpleLex.lex gppg.exe /no-lines /gplex SimpleYacc.y +pause diff --git a/Module6/packages.config b/Module6/packages.config index 7a0d545..cad472a 100644 --- a/Module6/packages.config +++ b/Module6/packages.config @@ -1,4 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <packages> <package id="Newtonsoft.Json" version="11.0.2" targetFramework="net35-client" /> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> </packages> \ No newline at end of file diff --git a/Module7/ParserVistors.csproj b/Module7/ParserVistors.csproj index 21e6a21..e9c8936 100644 --- a/Module7/ParserVistors.csproj +++ b/Module7/ParserVistors.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">x86</Platform> @@ -14,6 +16,8 @@ <TargetFrameworkProfile> </TargetFrameworkProfile> <FileAlignment>512</FileAlignment> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PlatformTarget>x86</PlatformTarget> @@ -60,6 +64,9 @@ <Reference Include="Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <HintPath>C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.dll</HintPath> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> @@ -93,8 +100,16 @@ </ItemGroup> <ItemGroup> <None Include="app.config" /> + <None Include="packages.config" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> <!-- 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"> diff --git a/Module7/ProgramTree.cs b/Module7/ProgramTree.cs index e48dcb5..f2a07d3 100644 --- a/Module7/ProgramTree.cs +++ b/Module7/ProgramTree.cs @@ -142,4 +142,32 @@ namespace ProgramTree v.VisitVarDefNode(this); } } + + public class IfNode : StatementNode + { + public ExprNode Expr { get; set; } + + public StatementNode ThenStat { get; set; } + + public StatementNode ElseStat { get; set; } + + // полная форма + public IfNode(ExprNode expr, StatementNode thenNode, StatementNode elseNode) + { + Expr = expr; + ThenStat = thenNode; + ElseStat = elseNode; + } + + // неполная форма + public IfNode(ExprNode expr, StatementNode thenNode) : this(expr, thenNode, null) + { + } + + public override void Visit(Visitor v) + { + v.VisitIfNode(this); + } + } + } \ No newline at end of file diff --git a/Module7/SimpleLex.cs b/Module7/SimpleLex.cs index 98388ef..640275d 100644 --- a/Module7/SimpleLex.cs +++ b/Module7/SimpleLex.cs @@ -1,14 +1,10 @@ // // This CSharp output file generated by Gardens Point LEX -// Gardens Point LEX (GPLEX) is Copyright (c) John Gough, QUT 2006-2014. -// Output produced by GPLEX is the property of the user. -// See accompanying file GPLEXcopyright.rtf. -// -// GPLEX Version: 1.2.2 -// Machine: MAINHOMEPC2 -// DateTime: 30.09.2018 18:17:27 -// UserName: someone -// GPLEX input file <SimpleLex.lex - 24.09.2018 23:47:03> +// Version: 1.1.3.301 +// Machine: WIN-51KGPO1PTR9 +// DateTime: 04.12.2022 15:32:10 +// UserName: ????????????? +// GPLEX input file <SimpleLex.lex> // GPLEX frame file <embedded resource> // // Option settings: unicode, parser, minimize @@ -17,8 +13,8 @@ // // -// Revised backup code -// Version 1.2.1 of 24-June-2013 +// Experimental embedded frame +// Version 1.1.3 of 18-April-2010 // // #define BACKUP @@ -305,7 +301,8 @@ int NextState() { public Scanner(Stream file, string codepage) { SetSource(file, CodePageHandling.GetCodePage(codepage)); - } + } + #endif // !NOFILES public Scanner() { } @@ -333,7 +330,7 @@ int NextState() { if (next < 0xDC00 || next > 0xDFFF) code = ScanBuff.UnicodeReplacementChar; else - code = (0x10000 + ((code & 0x3FF) << 10) + (next & 0x3FF)); + code = (0x10000 + (code & 0x3FF << 10) + (next & 0x3FF)); } #endif cCol++; @@ -386,7 +383,9 @@ int NextState() { GetCode(); } +#if !NOFILES // ================ LineBuffer Initialization =================== + /// <summary> /// Create and initialize a LineBuff buffer object for this scanner /// </summary> @@ -400,7 +399,6 @@ int NextState() { GetCode(); } -#if !NOFILES // =============== StreamBuffer Initialization ================== /// <summary> @@ -502,12 +500,6 @@ int NextState() { } } - /// <summary> - /// Discards all but the first "n" codepoints in the recognized pattern. - /// Resets the buffer position so that only n codepoints have been consumed; - /// yytext is also re-evaluated. - /// </summary> - /// <param name="n">The number of codepoints to consume</param> [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] void yyless(int n) { @@ -527,10 +519,6 @@ int NextState() { // but it does not seem possible to re-establish // the correct column counts except by going forward. // - /// <summary> - /// Removes the last "n" code points from the pattern. - /// </summary> - /// <param name="n">The number to remove</param> [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] void _yytrunc(int n) { yyless(yyleng - n); } @@ -543,23 +531,18 @@ int NextState() { // can't use (tokEPos - tokPos) because of the // possibility of surrogate pairs in the token. // - /// <summary> - /// The length of the pattern in codepoints (not the same as - /// string-length if the pattern contains any surrogate pairs). - /// </summary> [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 -#if BYTEMODE - return tokEPos - tokPos; -#else - { + else { int ch; int count = 0; int save = buffer.Pos; @@ -568,7 +551,7 @@ int NextState() { ch = buffer.Read(); if (!char.IsHighSurrogate((char)ch)) count++; } while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile); - buffer.Pos = save; + buffer.Pos = save; return count; } #endif // BYTEMODE @@ -593,56 +576,65 @@ int NextState() { // ============== The main tokenizer code ================= - int Scan() { + int Scan() + { try { - for (; ; ) { - int next; // next state to enter + for (; ; ) + { + int next; // next state to enter +#if BACKUP + Result rslt = Result.noMatch; +#endif // BACKUP #if LEFTANCHORS - for (;;) { + 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... + if ((next = NextState()) != goStart) + break; // LOOP EXIT HERE... GetCode(); } #else // !LEFTANCHORS state = currentStart; - while ((next = NextState()) == goStart) { + 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(); + GetCode(); + + while ((next = NextState()) > eofNum) // Exit for goStart AND for eofNum #if BACKUP - bool contextSaved = false; - while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum - if (state <= maxAccept && next > maxAccept) { // need to prepare backup data - // Store data for the *latest* accept state that was found. - SaveStateAndPos( ref ctx ); - contextSaved = true; + 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; } - state = next; - GetCode(); - } - if (state > maxAccept && contextSaved) - RestoreStateAndPos( ref ctx ); -#else // BACKUP - while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum - state = next; - GetCode(); - } + else #endif // BACKUP - if (state <= maxAccept) { + { + state = next; + GetCode(); + } + if (state <= maxAccept) + { MarkEnd(); #region ActionSwitch -#pragma warning disable 162, 1522 +#pragma warning disable 162 switch (state) { case eofNum: @@ -706,7 +698,7 @@ yylval.dVal = double.Parse(yytext); default: break; } -#pragma warning restore 162, 1522 +#pragma warning restore 162 #endregion } } @@ -719,7 +711,29 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); } #if BACKUP - void SaveStateAndPos(ref Context ctx) { + 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; @@ -728,7 +742,8 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); ctx.cChr = code; } - void RestoreStateAndPos(ref Context ctx) { + void RestoreStateAndPos(ref Context ctx) + { buffer.Pos = ctx.bPos; readPos = ctx.rPos; cCol = ctx.cCol; @@ -736,7 +751,8 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); state = ctx.state; code = ctx.cChr; } -#endif // BACKUP + +#endif // BACKUP // ============= End of the tokenizer code ================ @@ -768,16 +784,16 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); #region UserCodeSection -public override void yyerror(string format, params object[] args) // îáðà áîòêà ñèГГІГ ГЄГ±ГЁГ·ГҐГ±ГЄГЁГµ îøèáîê +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)); + 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); + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); throw new LexException(errorMsg); } @@ -793,6 +809,10 @@ class ScannerHelper keywords.Add("cycle",(int)Tokens.CYCLE); keywords.Add("write",(int)Tokens.WRITE); keywords.Add("var",(int)Tokens.VAR); + keywords.Add("if",(int)Tokens.IF); + keywords.Add("then",(int)Tokens.THEN); + keywords.Add("else",(int)Tokens.ELSE); + } public static int GetIDToken(string s) { @@ -853,7 +873,6 @@ class ScannerHelper return new LineBuffer(source); } -#if (!NOFILES) public static ScanBuff GetBuffer(Stream source) { return new BuildBuffer(source); @@ -864,8 +883,7 @@ class ScannerHelper { return new BuildBuffer(source, fallbackCodePage); } -#endif // !BYTEMODE -#endif // !NOFILES +#endif } #region Buffer classes @@ -988,7 +1006,7 @@ class ScannerHelper { ix = lstart = 0; } - while (ix < numLines) + for (; ; ) { int len = line[ix].Length + 1; if (pos < lstart + len) break; @@ -1046,8 +1064,7 @@ class ScannerHelper { cPos = value; findIndex(cPos, out cLine, out curLineStart); - // cLine should be the *next* line after curLine. - curLine = (cLine < numLines ? line[cLine++] : ""); + curLine = line[cLine]; curLineEnd = curLineStart + curLine.Length; } } @@ -1055,7 +1072,7 @@ class ScannerHelper public override string ToString() { return "LineBuffer"; } } -#if (!NOFILES) + // ============================================================== // ===== class BuildBuff : for unicode text files ======== // ============================================================== @@ -1296,13 +1313,12 @@ class ScannerHelper } #endif // !BYTEMODE } -#endif // !NOFILES #endregion Buffer classes // ============================================================== // ============ class CodePageHandling ============= // ============================================================== -#if (!NOFILES) + public static class CodePageHandling { public static int GetCodePage(string option) @@ -1513,7 +1529,6 @@ class ScannerHelper #endif // !BYTEMODE #endregion -#endif // !NOFILES // End of code copied from embedded resource diff --git a/Module7/SimpleLex.lex b/Module7/SimpleLex.lex index 00dfa12..c0e8f5a 100644 --- a/Module7/SimpleLex.lex +++ b/Module7/SimpleLex.lex @@ -78,6 +78,10 @@ class ScannerHelper keywords.Add("cycle",(int)Tokens.CYCLE); keywords.Add("write",(int)Tokens.WRITE); keywords.Add("var",(int)Tokens.VAR); + keywords.Add("if",(int)Tokens.IF); + keywords.Add("then",(int)Tokens.THEN); + keywords.Add("else",(int)Tokens.ELSE); + } public static int GetIDToken(string s) { diff --git a/Module7/SimpleYacc.cs b/Module7/SimpleYacc.cs index e0ec2ad..844a50c 100644 --- a/Module7/SimpleYacc.cs +++ b/Module7/SimpleYacc.cs @@ -1,18 +1,17 @@ // This code was generated by the Gardens Point Parser Generator -// Copyright (c) Wayne Kelly, John Gough, QUT 2005-2014 +// Copyright (c) Wayne Kelly, QUT 2005-2010 // (see accompanying GPPGcopyright.rtf) -// GPPG version 1.5.2 -// Machine: MAINHOMEPC2 -// DateTime: 30.09.2018 18:17:29 -// UserName: someone -// Input file <SimpleYacc.y - 24.09.2018 23:47:03> +// GPPG version 1.3.6 +// Machine: WIN-51KGPO1PTR9 +// DateTime: 04.12.2022 15:32:11 +// UserName: ????????????? +// Input file <SimpleYacc.y> // options: no-lines gplex using System; using System.Collections.Generic; -using System.CodeDom.Compiler; using System.Globalization; using System.Text; using QUT.Gppg; @@ -21,10 +20,12 @@ using ProgramTree; namespace SimpleParser { -public enum Tokens {error=2,EOF=3,BEGIN=4,END=5,CYCLE=6, - ASSIGN=7,ASSIGNPLUS=8,ASSIGNMINUS=9,ASSIGNMULT=10,SEMICOLON=11,WRITE=12, - VAR=13,PLUS=14,MINUS=15,MULT=16,DIV=17,LPAREN=18, - RPAREN=19,COLUMN=20,INUM=21,RNUM=22,ID=23}; +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,IF=20,THEN=21,ELSE=22,INUM=23,RNUM=24, + ID=25}; public struct ValueType { @@ -37,124 +38,120 @@ public struct ValueType public BlockNode blVal; } // Abstract base class for GPLEX scanners -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] 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; } } -// Utility class for encapsulating token information -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] -public class ScanObj { - public int token; - public ValueType yylval; - public LexLocation yylloc; - public ScanObj( int t, ValueType val, LexLocation loc ) { - this.token = t; this.yylval = val; this.yylloc = loc; - } -} - -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] public class Parser: ShiftReduceParser<ValueType, LexLocation> { - // Verbatim content from SimpleYacc.y - 24.09.2018 23:47:03 -// ГќГІГЁ îáúÿâëåГГЁГї äîáà âëÿþòñÿ Гў êëà ññ GPPGParser, ïðåäñòà âëÿþùèé ñîáîé ïà ðñåð, ГЈГҐГåðèðóåìûé ñèñòåìîé gppg - public BlockNode root; // ÊîðГåâîé óçåë Г±ГЁГòà êñè÷åñêîãî äåðåâà + // 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 - 24.09.2018 23:47:03 + // End verbatim content from SimpleYacc.y #pragma warning disable 649 - private static Dictionary<int, string> aliases; + 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 Rule[] rules = new Rule[33]; + private static State[] states = new State[55]; private static string[] nonTerms = new string[] { "progr", "expr", "ident", "T", "F", "statement", "assign", "block", "cycle", - "write", "empty", "var", "varlist", "stlist", "$accept", "Anon@1", }; + "write", "empty", "var", "varlist", "if", "stlist", "$accept", "Anon@1", + }; static Parser() { - states[0] = new State(new int[]{4,4},new int[]{-1,1,-8,3}); - states[1] = new State(new int[]{3,2}); + 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[]{23,18,4,4,6,31,12,35,13,40,5,-11,11,-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[]{5,6,11,7}); - states[6] = new State(-23); - states[7] = new State(new int[]{23,18,4,4,6,31,12,35,13,40,5,-11,11,-11},new int[]{-6,8,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46}); + states[4] = new State(new int[]{25,18,3,4,5,31,11,35,12,40,20,48,4,-12,10,-12},new int[]{-15,5,-6,54,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46,-14,47}); + states[5] = new State(new int[]{4,6,10,7}); + states[6] = new State(-24); + states[7] = new State(new int[]{25,18,3,4,5,31,11,35,12,40,20,48,4,-12,10,-12},new int[]{-6,8,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46,-14,47}); states[8] = new State(-4); states[9] = new State(-5); - states[10] = new State(new int[]{7,11}); - states[11] = new State(new int[]{23,18,21,19,18,20},new int[]{-2,12,-4,28,-5,27,-3,17}); - states[12] = new State(new int[]{14,13,15,23,5,-13,11,-13}); - states[13] = new State(new int[]{23,18,21,19,18,20},new int[]{-4,14,-5,27,-3,17}); - states[14] = new State(new int[]{16,15,17,25,14,-14,15,-14,5,-14,11,-14,19,-14,23,-14,4,-14,6,-14,12,-14,13,-14}); - states[15] = new State(new int[]{23,18,21,19,18,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[]{23,18,21,19,18,20},new int[]{-2,21,-4,28,-5,27,-3,17}); - states[21] = new State(new int[]{19,22,14,13,15,23}); - states[22] = new State(-22); - states[23] = new State(new int[]{23,18,21,19,18,20},new int[]{-4,24,-5,27,-3,17}); - states[24] = new State(new int[]{16,15,17,25,14,-15,15,-15,5,-15,11,-15,19,-15,23,-15,4,-15,6,-15,12,-15,13,-15}); - states[25] = new State(new int[]{23,18,21,19,18,20},new int[]{-5,26,-3,17}); - states[26] = new State(-18); - states[27] = new State(-19); - states[28] = new State(new int[]{16,15,17,25,14,-16,15,-16,5,-16,11,-16,19,-16,23,-16,4,-16,6,-16,12,-16,13,-16}); + states[10] = new State(new int[]{6,11}); + states[11] = new State(new int[]{25,18,23,19,17,20},new int[]{-2,12,-4,28,-5,27,-3,17}); + states[12] = new State(new int[]{13,13,14,23,4,-14,10,-14,22,-14}); + states[13] = new State(new int[]{25,18,23,19,17,20},new int[]{-4,14,-5,27,-3,17}); + states[14] = new State(new int[]{15,15,16,25,13,-15,14,-15,4,-15,10,-15,22,-15,18,-15,25,-15,3,-15,5,-15,11,-15,12,-15,20,-15,21,-15}); + states[15] = new State(new int[]{25,18,23,19,17,20},new int[]{-5,16,-3,17}); + states[16] = new State(-18); + states[17] = new State(-21); + states[18] = new State(-13); + states[19] = new State(-22); + states[20] = new State(new int[]{25,18,23,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(-23); + states[23] = new State(new int[]{25,18,23,19,17,20},new int[]{-4,24,-5,27,-3,17}); + states[24] = new State(new int[]{15,15,16,25,13,-16,14,-16,4,-16,10,-16,22,-16,18,-16,25,-16,3,-16,5,-16,11,-16,12,-16,20,-16,21,-16}); + states[25] = new State(new int[]{25,18,23,19,17,20},new int[]{-5,26,-3,17}); + states[26] = new State(-19); + states[27] = new State(-20); + states[28] = new State(new int[]{15,15,16,25,13,-17,14,-17,4,-17,10,-17,22,-17,18,-17,25,-17,3,-17,5,-17,11,-17,12,-17,20,-17,21,-17}); states[29] = new State(-6); states[30] = new State(-7); - states[31] = new State(new int[]{23,18,21,19,18,20},new int[]{-2,32,-4,28,-5,27,-3,17}); - states[32] = new State(new int[]{14,13,15,23,23,18,4,4,6,31,12,35,13,40,5,-11,11,-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[31] = new State(new int[]{25,18,23,19,17,20},new int[]{-2,32,-4,28,-5,27,-3,17}); + states[32] = new State(new int[]{13,13,14,23,25,18,3,4,5,31,11,35,12,40,20,48,4,-12,10,-12,22,-12},new int[]{-6,33,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46,-14,47}); + states[33] = new State(-25); states[34] = new State(-8); - states[35] = new State(new int[]{18,36}); - states[36] = new State(new int[]{23,18,21,19,18,20},new int[]{-2,37,-4,28,-5,27,-3,17}); - states[37] = new State(new int[]{19,38,14,13,15,23}); - states[38] = new State(-25); + states[35] = new State(new int[]{17,36}); + states[36] = new State(new int[]{25,18,23,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(-26); states[39] = new State(-9); - states[40] = new State(-26,new int[]{-16,41}); - states[41] = new State(new int[]{23,18},new int[]{-13,42,-3,45}); - states[42] = new State(new int[]{20,43,5,-27,11,-27}); - states[43] = new State(new int[]{23,18},new int[]{-3,44}); - states[44] = new State(-29); - states[45] = new State(-28); + states[40] = new State(-27,new int[]{-17,41}); + states[41] = new State(new int[]{25,18},new int[]{-13,42,-3,45}); + states[42] = new State(new int[]{19,43,4,-28,10,-28,22,-28}); + states[43] = new State(new int[]{25,18},new int[]{-3,44}); + states[44] = new State(-30); + states[45] = new State(-29); states[46] = new State(-10); - states[47] = new State(-3); - - for (int sNo = 0; sNo < states.Length; sNo++) states[sNo].number = sNo; + states[47] = new State(-11); + states[48] = new State(new int[]{25,18,23,19,17,20},new int[]{-2,49,-4,28,-5,27,-3,17}); + states[49] = new State(new int[]{21,50,13,13,14,23}); + states[50] = new State(new int[]{25,18,3,4,5,31,11,35,12,40,20,48,4,-12,10,-12,22,-12},new int[]{-6,51,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46,-14,47}); + states[51] = new State(new int[]{22,52,4,-31,10,-31}); + states[52] = new State(new int[]{25,18,3,4,5,31,11,35,12,40,20,48,4,-12,10,-12,22,-12},new int[]{-6,53,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46,-14,47}); + states[53] = new State(-32); + states[54] = new State(-3); - rules[1] = new Rule(-15, new int[]{-1,3}); + rules[1] = new Rule(-16, 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,11,-6}); + rules[3] = new Rule(-15, new int[]{-6}); + rules[4] = new Rule(-15, new int[]{-15,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[]{23}); - rules[13] = new Rule(-7, new int[]{-3,7,-2}); - rules[14] = new Rule(-2, new int[]{-2,14,-4}); - rules[15] = new Rule(-2, new int[]{-2,15,-4}); - rules[16] = new Rule(-2, new int[]{-4}); - rules[17] = new Rule(-4, new int[]{-4,16,-5}); - rules[18] = new Rule(-4, new int[]{-4,17,-5}); - rules[19] = new Rule(-4, new int[]{-5}); - rules[20] = new Rule(-5, new int[]{-3}); - rules[21] = new Rule(-5, new int[]{21}); - rules[22] = new Rule(-5, new int[]{18,-2,19}); - rules[23] = new Rule(-8, new int[]{4,-14,5}); - rules[24] = new Rule(-9, new int[]{6,-2,-6}); - rules[25] = new Rule(-10, new int[]{12,18,-2,19}); - rules[26] = new Rule(-16, new int[]{}); - rules[27] = new Rule(-12, new int[]{13,-16,-13}); - rules[28] = new Rule(-13, new int[]{-3}); - rules[29] = new Rule(-13, new int[]{-13,20,-3}); + rules[11] = new Rule(-6, new int[]{-14}); + rules[12] = new Rule(-11, new int[]{}); + rules[13] = new Rule(-3, new int[]{25}); + rules[14] = new Rule(-7, new int[]{-3,6,-2}); + rules[15] = new Rule(-2, new int[]{-2,13,-4}); + rules[16] = new Rule(-2, new int[]{-2,14,-4}); + rules[17] = new Rule(-2, new int[]{-4}); + rules[18] = new Rule(-4, new int[]{-4,15,-5}); + rules[19] = new Rule(-4, new int[]{-4,16,-5}); + rules[20] = new Rule(-4, new int[]{-5}); + rules[21] = new Rule(-5, new int[]{-3}); + rules[22] = new Rule(-5, new int[]{23}); + rules[23] = new Rule(-5, new int[]{17,-2,18}); + rules[24] = new Rule(-8, new int[]{3,-15,4}); + rules[25] = new Rule(-9, new int[]{5,-2,-6}); + rules[26] = new Rule(-10, new int[]{11,17,-2,18}); + rules[27] = new Rule(-17, new int[]{}); + rules[28] = new Rule(-12, new int[]{12,-17,-13}); + rules[29] = new Rule(-13, new int[]{-3}); + rules[30] = new Rule(-13, new int[]{-13,19,-3}); + rules[31] = new Rule(-14, new int[]{20,-2,21,-6}); + rules[32] = new Rule(-14, new int[]{20,-2,21,-6,22,-6}); } protected override void Initialize() { @@ -166,7 +163,6 @@ public class Parser: ShiftReduceParser<ValueType, LexLocation> protected override void DoAction(int action) { -#pragma warning disable 162, 1522 switch (action) { case 2: // progr -> block @@ -201,85 +197,93 @@ public class Parser: ShiftReduceParser<ValueType, LexLocation> case 10: // statement -> empty { CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } break; - case 11: // empty -> /* empty */ + case 11: // statement -> if +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 12: // empty -> /* empty */ { CurrentSemanticValue.stVal = new EmptyNode(); } break; - case 12: // ident -> ID + case 13: // 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+" ГГҐ îïèñà ГГ "); + 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 + case 14: // 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 + case 15: // 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 + case 16: // expr -> expr, MINUS, T { CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'-'); } break; - case 16: // expr -> T + case 17: // expr -> T { CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal; } break; - case 17: // T -> T, MULT, F + case 18: // 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 + case 19: // T -> T, DIV, F { CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'/'); } break; - case 19: // T -> F + case 20: // T -> F { CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal; } break; - case 20: // F -> ident + case 21: // F -> ident { CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal as IdNode; } break; - case 21: // F -> INUM + case 22: // F -> INUM { CurrentSemanticValue.eVal = new IntNumNode(ValueStack[ValueStack.Depth-1].iVal); } break; - case 22: // F -> LPAREN, expr, RPAREN + case 23: // F -> LPAREN, expr, RPAREN { CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-2].eVal; } break; - case 23: // block -> BEGIN, stlist, END + case 24: // block -> BEGIN, stlist, END { CurrentSemanticValue.blVal = ValueStack[ValueStack.Depth-2].blVal; } break; - case 24: // cycle -> CYCLE, expr, statement + case 25: // 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 + case 26: // write -> WRITE, LPAREN, expr, RPAREN { CurrentSemanticValue.stVal = new WriteNode(ValueStack[ValueStack.Depth-2].eVal); } break; - case 26: // Anon@1 -> /* empty */ + case 27: // Anon@1 -> /* empty */ { InDefSect = true; } break; - case 27: // var -> VAR, Anon@1, varlist + case 28: // 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 + case 29: // varlist -> ident { CurrentSemanticValue.stVal = new VarDefNode(ValueStack[ValueStack.Depth-1].eVal as IdNode); } break; - case 29: // varlist -> varlist, COLUMN, ident + case 30: // 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; + case 31: // if -> IF, expr, THEN, statement +{ CurrentSemanticValue.stVal = new IfNode(ValueStack[ValueStack.Depth-3].eVal, ValueStack[ValueStack.Depth-1].stVal); } + break; + case 32: // if -> IF, expr, THEN, statement, ELSE, statement +{ CurrentSemanticValue.stVal = new IfNode(ValueStack[ValueStack.Depth-5].eVal, ValueStack[ValueStack.Depth-3].stVal, ValueStack[ValueStack.Depth-1].stVal); } + break; } -#pragma warning restore 162, 1522 } protected override string TerminalToString(int terminal) { - if (aliases != null && aliases.ContainsKey(terminal)) - return aliases[terminal]; + if (aliasses != null && aliasses.ContainsKey(terminal)) + return aliasses[terminal]; else if (((Tokens)terminal).ToString() != terminal.ToString(CultureInfo.InvariantCulture)) return ((Tokens)terminal).ToString(); else diff --git a/Module7/SimpleYacc.y b/Module7/SimpleYacc.y index 20087e0..a9130fc 100644 --- a/Module7/SimpleYacc.y +++ b/Module7/SimpleYacc.y @@ -24,13 +24,13 @@ %start progr -%token BEGIN END CYCLE ASSIGN ASSIGNPLUS ASSIGNMINUS ASSIGNMULT SEMICOLON WRITE VAR PLUS MINUS MULT DIV LPAREN RPAREN COLUMN +%token BEGIN END CYCLE ASSIGN ASSIGNPLUS ASSIGNMINUS ASSIGNMULT SEMICOLON WRITE VAR PLUS MINUS MULT DIV LPAREN RPAREN COLUMN IF THEN ELSE %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 <stVal> statement assign block cycle write empty var varlist if %type <blVal> stlist block %% @@ -55,6 +55,7 @@ statement: assign { $$ = $1; } | write { $$ = $1; } | var { $$ = $1; } | empty { $$ = $1; } + | if { $$ = $1; } ; empty : { $$ = new EmptyNode(); } @@ -114,6 +115,11 @@ varlist : ident $$ = $1; } ; + +if : IF expr THEN statement { $$ = new IfNode($2, $4); } + | IF expr THEN statement ELSE statement { $$ = new IfNode($2, $4, $6); } + ; + %% diff --git a/Module7/Visitors/AutoVisitor.cs b/Module7/Visitors/AutoVisitor.cs index 4bc0778..cb673ea 100644 --- a/Module7/Visitors/AutoVisitor.cs +++ b/Module7/Visitors/AutoVisitor.cs @@ -41,5 +41,14 @@ namespace SimpleLang.Visitors foreach (var v in w.vars) v.Visit(this); } + + public override void VisitIfNode(IfNode ifn) + { + ifn.Expr.Visit(this); + ifn.ThenStat.Visit(this); + if (ifn.ElseStat != null) + ifn.ElseStat.Visit(this); + } + } } diff --git a/Module7/Visitors/ChangeVarIdVisitor.cs b/Module7/Visitors/ChangeVarIdVisitor.cs index 7e8942d..b072be2 100644 --- a/Module7/Visitors/ChangeVarIdVisitor.cs +++ b/Module7/Visitors/ChangeVarIdVisitor.cs @@ -15,6 +15,13 @@ namespace SimpleLang.Visitors from = _from; to = _to; } - + + public override void VisitIdNode(IdNode id) + { + if (id.Name == from) + { + id.Name = to; + } + } } } diff --git a/Module7/Visitors/CommonlyUsedVarVisitor.cs b/Module7/Visitors/CommonlyUsedVarVisitor.cs index a73e3b6..2353d6f 100644 --- a/Module7/Visitors/CommonlyUsedVarVisitor.cs +++ b/Module7/Visitors/CommonlyUsedVarVisitor.cs @@ -8,9 +8,28 @@ namespace SimpleLang.Visitors { public class CommonlyUsedVarVisitor : AutoVisitor { + Dictionary<string, int> varUsages = new Dictionary<string, int>(); public string mostCommonlyUsedVar() { - throw new NotImplementedException(); + int maxCount = 0; + string maxVar = ""; + foreach (var item in varUsages) + { + if (item.Value > maxCount) + { + maxVar = item.Key; + maxCount = item.Value; + } + } + return maxVar; } + + public override void VisitIdNode(IdNode a) + { + if (!varUsages.ContainsKey(a.Name)) + varUsages[a.Name] = 1; + varUsages[a.Name]++; + } + } } diff --git a/Module7/Visitors/CountCyclesOpVisitor.cs b/Module7/Visitors/CountCyclesOpVisitor.cs index 5b5368b..dcbaec8 100644 --- a/Module7/Visitors/CountCyclesOpVisitor.cs +++ b/Module7/Visitors/CountCyclesOpVisitor.cs @@ -8,9 +8,37 @@ namespace SimpleLang.Visitors { public class CountCyclesOpVisitor : AutoVisitor { + public int amountOps = 0; + public int amountCycles = 0; + public bool isInCycle = false; public int MidCount() { - throw new NotImplementedException(); + return amountOps == 0 ? 0 : amountOps / amountCycles; + } + public override void VisitAssignNode(AssignNode a) + { + if (!isInCycle) return; + amountOps++; + } + + public override void VisitVarDefNode(VarDefNode w) + { + if (!isInCycle) return; + amountOps++; + } + + public override void VisitWriteNode(WriteNode w) + { + if (!isInCycle) return; + amountOps++; + } + + public override void VisitCycleNode(CycleNode c) + { + amountCycles++; + isInCycle = true; + c.Stat.Visit(this); + isInCycle = false; } } } diff --git a/Module7/Visitors/ExprComplexityVisitor.cs b/Module7/Visitors/ExprComplexityVisitor.cs index ef9f0b2..7ca5768 100644 --- a/Module7/Visitors/ExprComplexityVisitor.cs +++ b/Module7/Visitors/ExprComplexityVisitor.cs @@ -8,11 +8,48 @@ namespace SimpleLang.Visitors { public class ExprComplexityVisitor : AutoVisitor { - // СЃРїРёСЃРѕРє должен содержать сложность каждого выражения, встреченного РїСЂРё обычном РїРѕСЂСЏРґРєРµ РѕР±С…РѕРґР° AST - public List<int> getComplexityList() + List<int> complexity = new List<int>(); + int lastExprComplexity = 0; + + public override void VisitAssignNode(AssignNode a) + { + a.Expr.Visit(this); + complexity.Add(lastExprComplexity); + lastExprComplexity = 0; + } + + public override void VisitCycleNode(CycleNode c) + { + c.Expr.Visit(this); + complexity.Add(lastExprComplexity); + lastExprComplexity = 0; + c.Stat.Visit(this); + } + + public override void VisitWriteNode(WriteNode w) + { + w.Expr.Visit(this); + complexity.Add(lastExprComplexity); + lastExprComplexity = 0; + } + + public override void VisitBinOpNode(BinOpNode binop) { - throw new NotImplementedException(); + binop.Left.Visit(this); + if (binop.Op == '+' || binop.Op == '-') + { + lastExprComplexity += 1; + } + if (binop.Op == '*' || binop.Op == '/') + { + lastExprComplexity += 3; + } + binop.Right.Visit(this); } - } + public List<int> getComplexityList() + { + return complexity; + } + } } diff --git a/Module7/Visitors/MaxIfCycleNestVisitor.cs b/Module7/Visitors/MaxIfCycleNestVisitor.cs index c399a8e..349992b 100644 --- a/Module7/Visitors/MaxIfCycleNestVisitor.cs +++ b/Module7/Visitors/MaxIfCycleNestVisitor.cs @@ -10,5 +10,28 @@ namespace SimpleLang.Visitors public class MaxIfCycleNestVisitor : AutoVisitor { public int MaxNest = 0; + + private int currentNestLevel = 0; + + public override void VisitCycleNode(CycleNode c) + { + currentNestLevel++; + if (currentNestLevel > MaxNest) + MaxNest = currentNestLevel; + c.Stat.Visit(this); + currentNestLevel--; + } + + public override void VisitIfNode(IfNode ifn) + { + currentNestLevel++; + if (currentNestLevel > MaxNest) + MaxNest = currentNestLevel; + ifn.ThenStat.Visit(this); + if (ifn.ElseStat != null) + ifn.ElseStat.Visit(this); + currentNestLevel--; + } + } } \ No newline at end of file diff --git a/Module7/Visitors/MaxNestCyclesVisitor.cs b/Module7/Visitors/MaxNestCyclesVisitor.cs index e5c768b..e41e913 100644 --- a/Module7/Visitors/MaxNestCyclesVisitor.cs +++ b/Module7/Visitors/MaxNestCyclesVisitor.cs @@ -9,5 +9,18 @@ namespace SimpleLang.Visitors public class MaxNestCyclesVisitor : AutoVisitor { public int MaxNest = 0; + + private int currentNestLevel = 0; + public override void VisitCycleNode(CycleNode c) + { + currentNestLevel++; + if (currentNestLevel > MaxNest) + { + MaxNest = currentNestLevel; + } + c.Stat.Visit(this); + currentNestLevel--; + } + } } diff --git a/Module7/Visitors/PrettyPrintVisitor.cs b/Module7/Visitors/PrettyPrintVisitor.cs index 87892b1..9d899dd 100644 --- a/Module7/Visitors/PrettyPrintVisitor.cs +++ b/Module7/Visitors/PrettyPrintVisitor.cs @@ -84,5 +84,18 @@ namespace SimpleLang.Visitors for (int i = 1; i < w.vars.Count; i++) Text += ',' + w.vars[i].Name; } + public override void VisitIfNode(IfNode ifn) + { + Text += IndentStr() + "if "; + ifn.Expr.Visit(this); + Text += Environment.NewLine; + ifn.ThenStat.Visit(this); + + if (ifn.ElseStat == null) + return; + Text += Environment.NewLine; + ifn.ElseStat.Visit(this); + } + } } diff --git a/Module7/Visitors/Visitor.cs b/Module7/Visitors/Visitor.cs index b9dcae0..5c50fc1 100644 --- a/Module7/Visitors/Visitor.cs +++ b/Module7/Visitors/Visitor.cs @@ -17,5 +17,6 @@ namespace SimpleLang.Visitors public virtual void VisitWriteNode(WriteNode w) { } public virtual void VisitVarDefNode(VarDefNode w) { } public virtual void VisitEmptyNode(EmptyNode w) { } + public virtual void VisitIfNode(IfNode ifn) { } } } diff --git a/Module7/packages.config b/Module7/packages.config new file mode 100644 index 0000000..e68db37 --- /dev/null +++ b/Module7/packages.config @@ -0,0 +1,6 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> +</packages> \ No newline at end of file diff --git a/Module8/ParserGenerator.csproj b/Module8/ParserGenerator.csproj index a49c30a..fcf9adb 100644 --- a/Module8/ParserGenerator.csproj +++ b/Module8/ParserGenerator.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">x86</Platform> @@ -14,6 +16,8 @@ <TargetFrameworkProfile> </TargetFrameworkProfile> <FileAlignment>512</FileAlignment> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PlatformTarget>x86</PlatformTarget> @@ -60,6 +64,9 @@ <Reference Include="Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <HintPath>C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.dll</HintPath> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> @@ -90,8 +97,16 @@ </ItemGroup> <ItemGroup> <None Include="app.config" /> + <None Include="packages.config" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> <!-- 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"> diff --git a/Module8/ProgramTree.cs b/Module8/ProgramTree.cs index 500e940..8ffb89b 100644 --- a/Module8/ProgramTree.cs +++ b/Module8/ProgramTree.cs @@ -160,4 +160,35 @@ namespace ProgramTree v.VisitIfNode(this); } } + + public class WhileNode : StatementNode + { + public ExprNode Expr { get; set; } + public StatementNode Stat { get; set; } + public WhileNode(ExprNode expr, StatementNode stat) + { + Expr = expr; + Stat = stat; + } + public override void Visit(Visitor v) + { + v.VisitWhileNode(this); + } + } + + public class RepeatNode : StatementNode + { + public ExprNode Expr { get; set; } + public BlockNode StList { get; set; } + public RepeatNode(ExprNode expr, BlockNode stat) + { + Expr = expr; + StList = stat; + } + public override void Visit(Visitor v) + { + v.VisitRepeatNode(this); + } + } + } \ No newline at end of file diff --git a/Module8/SimpleLex.cs b/Module8/SimpleLex.cs index 124489e..09a5c3c 100644 --- a/Module8/SimpleLex.cs +++ b/Module8/SimpleLex.cs @@ -1,14 +1,10 @@ // // This CSharp output file generated by Gardens Point LEX -// Gardens Point LEX (GPLEX) is Copyright (c) John Gough, QUT 2006-2014. -// Output produced by GPLEX is the property of the user. -// See accompanying file GPLEXcopyright.rtf. -// -// GPLEX Version: 1.2.2 -// Machine: MAINHOMEPC2 -// DateTime: 30.09.2018 18:23:21 -// UserName: someone -// GPLEX input file <SimpleLex.lex - 30.09.2018 18:22:46> +// Version: 1.1.3.301 +// Machine: WIN-51KGPO1PTR9 +// DateTime: 04.12.2022 17:28:51 +// UserName: ????????????? +// GPLEX input file <SimpleLex.lex> // GPLEX frame file <embedded resource> // // Option settings: unicode, parser, minimize @@ -17,8 +13,8 @@ // // -// Revised backup code -// Version 1.2.1 of 24-June-2013 +// Experimental embedded frame +// Version 1.1.3 of 18-April-2010 // // #define BACKUP @@ -127,8 +123,8 @@ namespace SimpleScanner enum Result {accept, noMatch, contextFound}; - const int maxAccept = 17; - const int initial = 18; + const int maxAccept = 18; + const int initial = 19; const int eofNum = 0; const int goStart = -1; const int INITIAL = 0; @@ -165,24 +161,24 @@ namespace SimpleScanner } }; - static int[] startState = new int[] {18, 0}; + static int[] startState = new int[] {19, 0}; #region CompressedCharacterMap // - // There are 15 equivalence classes + // There are 16 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, +/* '\0' */ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, 15, +/* '\x10' */ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +/* '\x20' */ 0, 15, 15, 15, 15, 14, 15, 15, 11, 12, 9, 8, 13, 7, 2, 10, +/* '0' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 6, 15, 5, 15, 15, +/* '@' */ 15, 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, 15, 15, 15, 15, 3, +/* '`' */ 15, 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) @@ -190,20 +186,20 @@ namespace SimpleScanner if (code < 123) // '\0' <= code <= 'z' return mapC0[code - 0]; else // '{' <= code <= '\U0010FFFF' - return (sbyte)14; + return (sbyte)15; } #endregion - static Table[] NxS = new Table[20] { + static Table[] NxS = new Table[21] { /* NxS[ 0] */ new Table(0, 0, 0, null), -/* NxS[ 1] */ new Table(1, 2, -1, new sbyte[] {1, 19}), +/* NxS[ 1] */ new Table(1, 2, -1, new sbyte[] {1, 20}), /* 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[ 4] */ new Table(5, 1, -1, new sbyte[] {17}), /* 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[ 6] */ new Table(5, 1, -1, new sbyte[] {16}), +/* NxS[ 7] */ new Table(5, 1, -1, new sbyte[] {15}), +/* NxS[ 8] */ new Table(5, 1, -1, new sbyte[] {14}), /* NxS[ 9] */ new Table(0, 0, -1, null), /* NxS[ 10] */ new Table(0, 0, -1, null), /* NxS[ 11] */ new Table(0, 0, -1, null), @@ -212,10 +208,11 @@ namespace SimpleScanner /* 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}), +/* NxS[ 17] */ new Table(0, 0, -1, null), +/* NxS[ 18] */ new Table(1, 1, -1, new sbyte[] {18}), +/* NxS[ 19] */ new Table(1, 15, -1, new sbyte[] {1, 2, 3, 4, 2, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 2}), +/* NxS[ 20] */ new Table(1, 1, -1, new sbyte[] {18}), }; int NextState() { @@ -225,7 +222,7 @@ int NextState() { unchecked { int rslt; int idx = MapC(code) - NxS[state].min; - if (idx < 0) idx += 15; + if (idx < 0) idx += 16; if ((uint)idx >= (uint)NxS[state].rng) rslt = NxS[state].dflt; else rslt = NxS[state].nxt[idx]; return rslt; @@ -305,7 +302,8 @@ int NextState() { public Scanner(Stream file, string codepage) { SetSource(file, CodePageHandling.GetCodePage(codepage)); - } + } + #endif // !NOFILES public Scanner() { } @@ -333,7 +331,7 @@ int NextState() { if (next < 0xDC00 || next > 0xDFFF) code = ScanBuff.UnicodeReplacementChar; else - code = (0x10000 + ((code & 0x3FF) << 10) + (next & 0x3FF)); + code = (0x10000 + (code & 0x3FF << 10) + (next & 0x3FF)); } #endif cCol++; @@ -386,7 +384,9 @@ int NextState() { GetCode(); } +#if !NOFILES // ================ LineBuffer Initialization =================== + /// <summary> /// Create and initialize a LineBuff buffer object for this scanner /// </summary> @@ -400,7 +400,6 @@ int NextState() { GetCode(); } -#if !NOFILES // =============== StreamBuffer Initialization ================== /// <summary> @@ -502,12 +501,6 @@ int NextState() { } } - /// <summary> - /// Discards all but the first "n" codepoints in the recognized pattern. - /// Resets the buffer position so that only n codepoints have been consumed; - /// yytext is also re-evaluated. - /// </summary> - /// <param name="n">The number of codepoints to consume</param> [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] void yyless(int n) { @@ -527,10 +520,6 @@ int NextState() { // but it does not seem possible to re-establish // the correct column counts except by going forward. // - /// <summary> - /// Removes the last "n" code points from the pattern. - /// </summary> - /// <param name="n">The number to remove</param> [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] void _yytrunc(int n) { yyless(yyleng - n); } @@ -543,23 +532,18 @@ int NextState() { // can't use (tokEPos - tokPos) because of the // possibility of surrogate pairs in the token. // - /// <summary> - /// The length of the pattern in codepoints (not the same as - /// string-length if the pattern contains any surrogate pairs). - /// </summary> [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 -#if BYTEMODE - return tokEPos - tokPos; -#else - { + else { int ch; int count = 0; int save = buffer.Pos; @@ -568,7 +552,7 @@ int NextState() { ch = buffer.Read(); if (!char.IsHighSurrogate((char)ch)) count++; } while (buffer.Pos < tokEPos && ch != ScanBuff.EndOfFile); - buffer.Pos = save; + buffer.Pos = save; return count; } #endif // BYTEMODE @@ -593,56 +577,65 @@ int NextState() { // ============== The main tokenizer code ================= - int Scan() { + int Scan() + { try { - for (; ; ) { - int next; // next state to enter + for (; ; ) + { + int next; // next state to enter +#if BACKUP + Result rslt = Result.noMatch; +#endif // BACKUP #if LEFTANCHORS - for (;;) { + 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... + if ((next = NextState()) != goStart) + break; // LOOP EXIT HERE... GetCode(); } #else // !LEFTANCHORS state = currentStart; - while ((next = NextState()) == goStart) { + 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(); + GetCode(); + + while ((next = NextState()) > eofNum) // Exit for goStart AND for eofNum #if BACKUP - bool contextSaved = false; - while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum - if (state <= maxAccept && next > maxAccept) { // need to prepare backup data - // Store data for the *latest* accept state that was found. - SaveStateAndPos( ref ctx ); - contextSaved = true; + 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; } - state = next; - GetCode(); - } - if (state > maxAccept && contextSaved) - RestoreStateAndPos( ref ctx ); -#else // BACKUP - while ((next = NextState()) > eofNum) { // Exit for goStart AND for eofNum - state = next; - GetCode(); - } + else #endif // BACKUP - if (state <= maxAccept) { + { + state = next; + GetCode(); + } + if (state <= maxAccept) + { MarkEnd(); #region ActionSwitch -#pragma warning disable 162, 1522 +#pragma warning disable 162 switch (state) { case eofNum: @@ -688,25 +681,28 @@ return (int)Tokens.RPAREN; return (int)Tokens.COLUMN; break; case 13: -return (int)Tokens.ASSIGNMULT; +return (int)Tokens.MOD; break; case 14: -return (int)Tokens.ASSIGNPLUS; +return (int)Tokens.ASSIGNMULT; break; case 15: -return (int)Tokens.ASSIGNMINUS; +return (int)Tokens.ASSIGNPLUS; break; case 16: -return (int)Tokens.ASSIGN; +return (int)Tokens.ASSIGNMINUS; break; case 17: +return (int)Tokens.ASSIGN; + break; + case 18: yylval.dVal = double.Parse(yytext); return (int)Tokens.RNUM; break; default: break; } -#pragma warning restore 162, 1522 +#pragma warning restore 162 #endregion } } @@ -719,7 +715,29 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); } #if BACKUP - void SaveStateAndPos(ref Context ctx) { + 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; @@ -728,7 +746,8 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); ctx.cChr = code; } - void RestoreStateAndPos(ref Context ctx) { + void RestoreStateAndPos(ref Context ctx) + { buffer.Pos = ctx.bPos; readPos = ctx.rPos; cCol = ctx.cCol; @@ -736,7 +755,8 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); state = ctx.state; code = ctx.cChr; } -#endif // BACKUP + +#endif // BACKUP // ============= End of the tokenizer code ================ @@ -768,16 +788,16 @@ yylloc = new LexLocation(tokLin, tokCol, tokELin, tokECol); #region UserCodeSection -public override void yyerror(string format, params object[] args) // îáðà áîòêà ñèГГІГ ГЄГ±ГЁГ·ГҐГ±ГЄГЁГµ îøèáîê +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)); + 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); + string errorMsg = string.Format("({0},{1}): Неизвестный символ {2}", yyline, yycol, yytext); throw new LexException(errorMsg); } @@ -793,6 +813,15 @@ class ScannerHelper keywords.Add("cycle",(int)Tokens.CYCLE); keywords.Add("write",(int)Tokens.WRITE); keywords.Add("var",(int)Tokens.VAR); + keywords.Add("if", (int)Tokens.IF); + keywords.Add("then", (int)Tokens.THEN); + keywords.Add("else", (int)Tokens.ELSE); + keywords.Add("while", (int)Tokens.WHILE); + keywords.Add("do", (int)Tokens.DO); + keywords.Add("repeat", (int)Tokens.REPEAT); + keywords.Add("until", (int)Tokens.UNTIL); + + } public static int GetIDToken(string s) { @@ -853,7 +882,6 @@ class ScannerHelper return new LineBuffer(source); } -#if (!NOFILES) public static ScanBuff GetBuffer(Stream source) { return new BuildBuffer(source); @@ -864,8 +892,7 @@ class ScannerHelper { return new BuildBuffer(source, fallbackCodePage); } -#endif // !BYTEMODE -#endif // !NOFILES +#endif } #region Buffer classes @@ -988,7 +1015,7 @@ class ScannerHelper { ix = lstart = 0; } - while (ix < numLines) + for (; ; ) { int len = line[ix].Length + 1; if (pos < lstart + len) break; @@ -1046,8 +1073,7 @@ class ScannerHelper { cPos = value; findIndex(cPos, out cLine, out curLineStart); - // cLine should be the *next* line after curLine. - curLine = (cLine < numLines ? line[cLine++] : ""); + curLine = line[cLine]; curLineEnd = curLineStart + curLine.Length; } } @@ -1055,7 +1081,7 @@ class ScannerHelper public override string ToString() { return "LineBuffer"; } } -#if (!NOFILES) + // ============================================================== // ===== class BuildBuff : for unicode text files ======== // ============================================================== @@ -1296,13 +1322,12 @@ class ScannerHelper } #endif // !BYTEMODE } -#endif // !NOFILES #endregion Buffer classes // ============================================================== // ============ class CodePageHandling ============= // ============================================================== -#if (!NOFILES) + public static class CodePageHandling { public static int GetCodePage(string option) @@ -1513,7 +1538,6 @@ class ScannerHelper #endif // !BYTEMODE #endregion -#endif // !NOFILES // End of code copied from embedded resource diff --git a/Module8/SimpleLex.lex b/Module8/SimpleLex.lex index 00dfa12..4a1d430 100644 --- a/Module8/SimpleLex.lex +++ b/Module8/SimpleLex.lex @@ -42,6 +42,7 @@ ID {Alpha}{AlphaDigit}* "(" { return (int)Tokens.LPAREN; } ")" { return (int)Tokens.RPAREN; } "," { return (int)Tokens.COLUMN; } +"%" { return (int)Tokens.MOD; } [^ \r\n] { LexError(); @@ -78,6 +79,15 @@ class ScannerHelper keywords.Add("cycle",(int)Tokens.CYCLE); keywords.Add("write",(int)Tokens.WRITE); keywords.Add("var",(int)Tokens.VAR); + keywords.Add("if", (int)Tokens.IF); + keywords.Add("then", (int)Tokens.THEN); + keywords.Add("else", (int)Tokens.ELSE); + keywords.Add("while", (int)Tokens.WHILE); + keywords.Add("do", (int)Tokens.DO); + keywords.Add("repeat", (int)Tokens.REPEAT); + keywords.Add("until", (int)Tokens.UNTIL); + + } public static int GetIDToken(string s) { diff --git a/Module8/SimpleYacc.cs b/Module8/SimpleYacc.cs index 41990d1..b88992e 100644 --- a/Module8/SimpleYacc.cs +++ b/Module8/SimpleYacc.cs @@ -1,18 +1,17 @@ // This code was generated by the Gardens Point Parser Generator -// Copyright (c) Wayne Kelly, John Gough, QUT 2005-2014 +// Copyright (c) Wayne Kelly, QUT 2005-2010 // (see accompanying GPPGcopyright.rtf) -// GPPG version 1.5.2 -// Machine: MAINHOMEPC2 -// DateTime: 30.09.2018 18:23:23 -// UserName: someone -// Input file <SimpleYacc.y - 30.09.2018 18:22:38> +// GPPG version 1.3.6 +// Machine: WIN-51KGPO1PTR9 +// DateTime: 04.12.2022 17:28:51 +// UserName: ????????????? +// Input file <SimpleYacc.y> // options: no-lines gplex using System; using System.Collections.Generic; -using System.CodeDom.Compiler; using System.Globalization; using System.Text; using QUT.Gppg; @@ -21,10 +20,12 @@ using ProgramTree; namespace SimpleParser { -public enum Tokens {error=2,EOF=3,BEGIN=4,END=5,CYCLE=6, - ASSIGN=7,ASSIGNPLUS=8,ASSIGNMINUS=9,ASSIGNMULT=10,SEMICOLON=11,WRITE=12, - VAR=13,PLUS=14,MINUS=15,MULT=16,DIV=17,LPAREN=18, - RPAREN=19,COLUMN=20,INUM=21,RNUM=22,ID=23}; +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,MOD=20,IF=21,THEN=22,ELSE=23,WHILE=24, + DO=25,REPEAT=26,UNTIL=27,INUM=28,RNUM=29,ID=30}; public struct ValueType { @@ -37,124 +38,137 @@ public struct ValueType public BlockNode blVal; } // Abstract base class for GPLEX scanners -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] 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; } } -// Utility class for encapsulating token information -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] -public class ScanObj { - public int token; - public ValueType yylval; - public LexLocation yylloc; - public ScanObj( int t, ValueType val, LexLocation loc ) { - this.token = t; this.yylval = val; this.yylloc = loc; - } -} - -[GeneratedCodeAttribute( "Gardens Point Parser Generator", "1.5.2")] public class Parser: ShiftReduceParser<ValueType, LexLocation> { - // Verbatim content from SimpleYacc.y - 30.09.2018 18:22:38 -// ГќГІГЁ îáúÿâëåГГЁГї äîáà âëÿþòñÿ Гў êëà ññ GPPGParser, ïðåäñòà âëÿþùèé ñîáîé ïà ðñåð, ГЈГҐГåðèðóåìûé ñèñòåìîé gppg - public BlockNode root; // ÊîðГåâîé óçåë Г±ГЁГòà êñè÷åñêîãî äåðåâà + // 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 - 30.09.2018 18:22:38 + // End verbatim content from SimpleYacc.y #pragma warning disable 649 - private static Dictionary<int, string> aliases; + 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 Rule[] rules = new Rule[38]; + private static State[] states = new State[67]; private static string[] nonTerms = new string[] { "progr", "expr", "ident", "T", "F", "statement", "assign", "block", "cycle", - "write", "empty", "var", "varlist", "stlist", "$accept", "Anon@1", }; + "write", "empty", "var", "varlist", "if", "while", "repeat", "stlist", + "$accept", "Anon@1", }; static Parser() { - states[0] = new State(new int[]{4,4},new int[]{-1,1,-8,3}); - states[1] = new State(new int[]{3,2}); + 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[]{23,18,4,4,6,31,12,35,13,40,5,-11,11,-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[]{5,6,11,7}); - states[6] = new State(-23); - states[7] = new State(new int[]{23,18,4,4,6,31,12,35,13,40,5,-11,11,-11},new int[]{-6,8,-7,9,-3,10,-8,29,-9,30,-10,34,-12,39,-11,46}); + states[4] = new State(new int[]{30,18,3,4,5,33,11,37,12,42,21,50,24,57,26,62,4,-14,10,-14},new int[]{-17,5,-6,66,-7,9,-3,10,-8,31,-9,32,-10,36,-12,41,-11,48,-14,49,-15,56,-16,61}); + states[5] = new State(new int[]{4,6,10,7}); + states[6] = new State(-27); + states[7] = new State(new int[]{30,18,3,4,5,33,11,37,12,42,21,50,24,57,26,62,4,-14,10,-14,27,-14},new int[]{-6,8,-7,9,-3,10,-8,31,-9,32,-10,36,-12,41,-11,48,-14,49,-15,56,-16,61}); states[8] = new State(-4); states[9] = new State(-5); - states[10] = new State(new int[]{7,11}); - states[11] = new State(new int[]{23,18,21,19,18,20},new int[]{-2,12,-4,28,-5,27,-3,17}); - states[12] = new State(new int[]{14,13,15,23,5,-13,11,-13}); - states[13] = new State(new int[]{23,18,21,19,18,20},new int[]{-4,14,-5,27,-3,17}); - states[14] = new State(new int[]{16,15,17,25,14,-14,15,-14,5,-14,11,-14,19,-14,23,-14,4,-14,6,-14,12,-14,13,-14}); - states[15] = new State(new int[]{23,18,21,19,18,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[]{23,18,21,19,18,20},new int[]{-2,21,-4,28,-5,27,-3,17}); - states[21] = new State(new int[]{19,22,14,13,15,23}); - states[22] = new State(-22); - states[23] = new State(new int[]{23,18,21,19,18,20},new int[]{-4,24,-5,27,-3,17}); - states[24] = new State(new int[]{16,15,17,25,14,-15,15,-15,5,-15,11,-15,19,-15,23,-15,4,-15,6,-15,12,-15,13,-15}); - states[25] = new State(new int[]{23,18,21,19,18,20},new int[]{-5,26,-3,17}); - states[26] = new State(-18); - states[27] = new State(-19); - states[28] = new State(new int[]{16,15,17,25,14,-16,15,-16,5,-16,11,-16,19,-16,23,-16,4,-16,6,-16,12,-16,13,-16}); - states[29] = new State(-6); - states[30] = new State(-7); - states[31] = new State(new int[]{23,18,21,19,18,20},new int[]{-2,32,-4,28,-5,27,-3,17}); - states[32] = new State(new int[]{14,13,15,23,23,18,4,4,6,31,12,35,13,40,5,-11,11,-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[]{18,36}); - states[36] = new State(new int[]{23,18,21,19,18,20},new int[]{-2,37,-4,28,-5,27,-3,17}); - states[37] = new State(new int[]{19,38,14,13,15,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[]{23,18},new int[]{-13,42,-3,45}); - states[42] = new State(new int[]{20,43,5,-27,11,-27}); - states[43] = new State(new int[]{23,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); - - for (int sNo = 0; sNo < states.Length; sNo++) states[sNo].number = sNo; + states[10] = new State(new int[]{6,11}); + states[11] = new State(new int[]{30,18,28,19,17,20},new int[]{-2,12,-4,30,-5,29,-3,17}); + states[12] = new State(new int[]{13,13,14,23,4,-16,10,-16,27,-16,23,-16}); + states[13] = new State(new int[]{30,18,28,19,17,20},new int[]{-4,14,-5,29,-3,17}); + states[14] = new State(new int[]{15,15,16,25,20,27,13,-17,14,-17,4,-17,10,-17,27,-17,23,-17,18,-17,30,-17,3,-17,5,-17,11,-17,12,-17,21,-17,24,-17,26,-17,22,-17,25,-17}); + states[15] = new State(new int[]{30,18,28,19,17,20},new int[]{-5,16,-3,17}); + states[16] = new State(-20); + states[17] = new State(-24); + states[18] = new State(-15); + states[19] = new State(-25); + states[20] = new State(new int[]{30,18,28,19,17,20},new int[]{-2,21,-4,30,-5,29,-3,17}); + states[21] = new State(new int[]{18,22,13,13,14,23}); + states[22] = new State(-26); + states[23] = new State(new int[]{30,18,28,19,17,20},new int[]{-4,24,-5,29,-3,17}); + states[24] = new State(new int[]{15,15,16,25,20,27,13,-18,14,-18,4,-18,10,-18,27,-18,23,-18,18,-18,30,-18,3,-18,5,-18,11,-18,12,-18,21,-18,24,-18,26,-18,22,-18,25,-18}); + states[25] = new State(new int[]{30,18,28,19,17,20},new int[]{-5,26,-3,17}); + states[26] = new State(-21); + states[27] = new State(new int[]{30,18,28,19,17,20},new int[]{-5,28,-3,17}); + states[28] = new State(-22); + states[29] = new State(-23); + states[30] = new State(new int[]{15,15,16,25,20,27,13,-19,14,-19,4,-19,10,-19,27,-19,23,-19,18,-19,30,-19,3,-19,5,-19,11,-19,12,-19,21,-19,24,-19,26,-19,22,-19,25,-19}); + states[31] = new State(-6); + states[32] = new State(-7); + states[33] = new State(new int[]{30,18,28,19,17,20},new int[]{-2,34,-4,30,-5,29,-3,17}); + states[34] = new State(new int[]{13,13,14,23,30,18,3,4,5,33,11,37,12,42,21,50,24,57,26,62,4,-14,10,-14,27,-14,23,-14},new int[]{-6,35,-7,9,-3,10,-8,31,-9,32,-10,36,-12,41,-11,48,-14,49,-15,56,-16,61}); + states[35] = new State(-28); + states[36] = new State(-8); + states[37] = new State(new int[]{17,38}); + states[38] = new State(new int[]{30,18,28,19,17,20},new int[]{-2,39,-4,30,-5,29,-3,17}); + states[39] = new State(new int[]{18,40,13,13,14,23}); + states[40] = new State(-29); + states[41] = new State(-9); + states[42] = new State(-30,new int[]{-19,43}); + states[43] = new State(new int[]{30,18},new int[]{-13,44,-3,47}); + states[44] = new State(new int[]{19,45,4,-31,10,-31,27,-31,23,-31}); + states[45] = new State(new int[]{30,18},new int[]{-3,46}); + states[46] = new State(-33); + states[47] = new State(-32); + states[48] = new State(-10); + states[49] = new State(-11); + states[50] = new State(new int[]{30,18,28,19,17,20},new int[]{-2,51,-4,30,-5,29,-3,17}); + states[51] = new State(new int[]{22,52,13,13,14,23}); + states[52] = new State(new int[]{30,18,3,4,5,33,11,37,12,42,21,50,24,57,26,62,4,-14,10,-14,27,-14,23,-14},new int[]{-6,53,-7,9,-3,10,-8,31,-9,32,-10,36,-12,41,-11,48,-14,49,-15,56,-16,61}); + states[53] = new State(new int[]{23,54,4,-34,10,-34,27,-34}); + states[54] = new State(new int[]{30,18,3,4,5,33,11,37,12,42,21,50,24,57,26,62,4,-14,10,-14,27,-14,23,-14},new int[]{-6,55,-7,9,-3,10,-8,31,-9,32,-10,36,-12,41,-11,48,-14,49,-15,56,-16,61}); + states[55] = new State(-35); + states[56] = new State(-12); + states[57] = new State(new int[]{30,18,28,19,17,20},new int[]{-2,58,-4,30,-5,29,-3,17}); + states[58] = new State(new int[]{25,59,13,13,14,23}); + states[59] = new State(new int[]{30,18,3,4,5,33,11,37,12,42,21,50,24,57,26,62,4,-14,10,-14,27,-14,23,-14},new int[]{-6,60,-7,9,-3,10,-8,31,-9,32,-10,36,-12,41,-11,48,-14,49,-15,56,-16,61}); + states[60] = new State(-36); + states[61] = new State(-13); + states[62] = new State(new int[]{30,18,3,4,5,33,11,37,12,42,21,50,24,57,26,62,27,-14,10,-14},new int[]{-17,63,-6,66,-7,9,-3,10,-8,31,-9,32,-10,36,-12,41,-11,48,-14,49,-15,56,-16,61}); + states[63] = new State(new int[]{27,64,10,7}); + states[64] = new State(new int[]{30,18,28,19,17,20},new int[]{-2,65,-4,30,-5,29,-3,17}); + states[65] = new State(new int[]{13,13,14,23,4,-37,10,-37,27,-37,23,-37}); + states[66] = new State(-3); - rules[1] = new Rule(-15, new int[]{-1,3}); + rules[1] = new Rule(-18, 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,11,-6}); + rules[3] = new Rule(-17, new int[]{-6}); + rules[4] = new Rule(-17, new int[]{-17,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[]{23}); - rules[13] = new Rule(-7, new int[]{-3,7,-2}); - rules[14] = new Rule(-2, new int[]{-2,14,-4}); - rules[15] = new Rule(-2, new int[]{-2,15,-4}); - rules[16] = new Rule(-2, new int[]{-4}); - rules[17] = new Rule(-4, new int[]{-4,16,-5}); - rules[18] = new Rule(-4, new int[]{-4,17,-5}); - rules[19] = new Rule(-4, new int[]{-5}); - rules[20] = new Rule(-5, new int[]{-3}); - rules[21] = new Rule(-5, new int[]{21}); - rules[22] = new Rule(-5, new int[]{18,-2,19}); - rules[23] = new Rule(-8, new int[]{4,-14,5}); - rules[24] = new Rule(-9, new int[]{6,-2,-6}); - rules[25] = new Rule(-10, new int[]{12,18,-2,19}); - rules[26] = new Rule(-16, new int[]{}); - rules[27] = new Rule(-12, new int[]{13,-16,-13}); - rules[28] = new Rule(-13, new int[]{-3}); - rules[29] = new Rule(-13, new int[]{-13,20,-3}); + rules[11] = new Rule(-6, new int[]{-14}); + rules[12] = new Rule(-6, new int[]{-15}); + rules[13] = new Rule(-6, new int[]{-16}); + rules[14] = new Rule(-11, new int[]{}); + rules[15] = new Rule(-3, new int[]{30}); + rules[16] = new Rule(-7, new int[]{-3,6,-2}); + rules[17] = new Rule(-2, new int[]{-2,13,-4}); + rules[18] = new Rule(-2, new int[]{-2,14,-4}); + rules[19] = new Rule(-2, new int[]{-4}); + rules[20] = new Rule(-4, new int[]{-4,15,-5}); + rules[21] = new Rule(-4, new int[]{-4,16,-5}); + rules[22] = new Rule(-4, new int[]{-4,20,-5}); + rules[23] = new Rule(-4, new int[]{-5}); + rules[24] = new Rule(-5, new int[]{-3}); + rules[25] = new Rule(-5, new int[]{28}); + rules[26] = new Rule(-5, new int[]{17,-2,18}); + rules[27] = new Rule(-8, new int[]{3,-17,4}); + rules[28] = new Rule(-9, new int[]{5,-2,-6}); + rules[29] = new Rule(-10, new int[]{11,17,-2,18}); + rules[30] = new Rule(-19, new int[]{}); + rules[31] = new Rule(-12, new int[]{12,-19,-13}); + rules[32] = new Rule(-13, new int[]{-3}); + rules[33] = new Rule(-13, new int[]{-13,19,-3}); + rules[34] = new Rule(-14, new int[]{21,-2,22,-6}); + rules[35] = new Rule(-14, new int[]{21,-2,22,-6,23,-6}); + rules[36] = new Rule(-15, new int[]{24,-2,25,-6}); + rules[37] = new Rule(-16, new int[]{26,-17,27,-2}); } protected override void Initialize() { @@ -166,7 +180,6 @@ public class Parser: ShiftReduceParser<ValueType, LexLocation> protected override void DoAction(int action) { -#pragma warning disable 162, 1522 switch (action) { case 2: // progr -> block @@ -201,90 +214,114 @@ public class Parser: ShiftReduceParser<ValueType, LexLocation> case 10: // statement -> empty { CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } break; - case 11: // empty -> /* empty */ + case 11: // statement -> if +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 12: // statement -> while +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 13: // statement -> repeat +{ CurrentSemanticValue.stVal = ValueStack[ValueStack.Depth-1].stVal; } + break; + case 14: // empty -> /* empty */ { CurrentSemanticValue.stVal = new EmptyNode(); } break; - case 12: // ident -> ID + case 15: // 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+" ГГҐ îïèñà ГГ "); + 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 + case 16: // 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 + case 17: // 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 + case 18: // expr -> expr, MINUS, T { CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'-'); } break; - case 16: // expr -> T + case 19: // expr -> T { CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal; } break; - case 17: // T -> T, MULT, F + case 20: // 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 + case 21: // T -> T, DIV, F { CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'/'); } break; - case 19: // T -> F + case 22: // T -> T, MOD, F +{ CurrentSemanticValue.eVal = new BinOpNode(ValueStack[ValueStack.Depth-3].eVal,ValueStack[ValueStack.Depth-1].eVal,'%'); } + break; + case 23: // T -> F { CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal; } break; - case 20: // F -> ident + case 24: // F -> ident { CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-1].eVal as IdNode; } break; - case 21: // F -> INUM + case 25: // F -> INUM { CurrentSemanticValue.eVal = new IntNumNode(ValueStack[ValueStack.Depth-1].iVal); } break; - case 22: // F -> LPAREN, expr, RPAREN + case 26: // F -> LPAREN, expr, RPAREN { CurrentSemanticValue.eVal = ValueStack[ValueStack.Depth-2].eVal; } break; - case 23: // block -> BEGIN, stlist, END + case 27: // block -> BEGIN, stlist, END { CurrentSemanticValue.blVal = ValueStack[ValueStack.Depth-2].blVal; } break; - case 24: // cycle -> CYCLE, expr, statement + case 28: // 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 + case 29: // write -> WRITE, LPAREN, expr, RPAREN { CurrentSemanticValue.stVal = new WriteNode(ValueStack[ValueStack.Depth-2].eVal); } break; - case 26: // Anon@1 -> /* empty */ + case 30: // Anon@1 -> /* empty */ { InDefSect = true; } break; - case 27: // var -> VAR, Anon@1, varlist + case 31: // 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 + case 32: // varlist -> ident { CurrentSemanticValue.stVal = new VarDefNode(ValueStack[ValueStack.Depth-1].eVal as IdNode); } break; - case 29: // varlist -> varlist, COLUMN, ident + case 33: // 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; + case 34: // if -> IF, expr, THEN, statement +{ CurrentSemanticValue.stVal = new IfNode(ValueStack[ValueStack.Depth-3].eVal, ValueStack[ValueStack.Depth-1].stVal); } + break; + case 35: // if -> IF, expr, THEN, statement, ELSE, statement +{ CurrentSemanticValue.stVal = new IfNode(ValueStack[ValueStack.Depth-5].eVal, ValueStack[ValueStack.Depth-3].stVal, ValueStack[ValueStack.Depth-1].stVal); } + break; + case 36: // while -> WHILE, expr, DO, statement +{ CurrentSemanticValue.stVal = new WhileNode(ValueStack[ValueStack.Depth-3].eVal, ValueStack[ValueStack.Depth-1].stVal); } + break; + case 37: // repeat -> REPEAT, stlist, UNTIL, expr +{ CurrentSemanticValue.stVal = new RepeatNode(ValueStack[ValueStack.Depth-1].eVal, ValueStack[ValueStack.Depth-3].blVal); } + break; } -#pragma warning restore 162, 1522 } protected override string TerminalToString(int terminal) { - if (aliases != null && aliases.ContainsKey(terminal)) - return aliases[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/SimpleYacc.y b/Module8/SimpleYacc.y index 20087e0..1e4d1d0 100644 --- a/Module8/SimpleYacc.y +++ b/Module8/SimpleYacc.y @@ -24,13 +24,13 @@ %start progr -%token BEGIN END CYCLE ASSIGN ASSIGNPLUS ASSIGNMINUS ASSIGNMULT SEMICOLON WRITE VAR PLUS MINUS MULT DIV LPAREN RPAREN COLUMN +%token BEGIN END CYCLE ASSIGN ASSIGNPLUS ASSIGNMINUS ASSIGNMULT SEMICOLON WRITE VAR PLUS MINUS MULT DIV LPAREN RPAREN COLUMN MOD IF THEN ELSE WHILE DO REPEAT UNTIL %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 <stVal> statement assign block cycle write empty var varlist if while repeat %type <blVal> stlist block %% @@ -55,6 +55,10 @@ statement: assign { $$ = $1; } | write { $$ = $1; } | var { $$ = $1; } | empty { $$ = $1; } + | if { $$ = $1; } + | while { $$ = $1; } + | repeat { $$ = $1; } + ; empty : { $$ = new EmptyNode(); } @@ -79,6 +83,7 @@ expr : expr PLUS T { $$ = new BinOpNode($1,$3,'+'); } T : T MULT F { $$ = new BinOpNode($1,$3,'*'); } | T DIV F { $$ = new BinOpNode($1,$3,'/'); } + | T MOD F { $$ = new BinOpNode($1,$3,'%'); } | F { $$ = $1; } ; @@ -114,6 +119,18 @@ varlist : ident $$ = $1; } ; + +if : IF expr THEN statement { $$ = new IfNode($2, $4); } + | IF expr THEN statement ELSE statement { $$ = new IfNode($2, $4, $6); } + ; + +while : WHILE expr DO statement { $$ = new WhileNode($2, $4); } + ; + +repeat : REPEAT stlist UNTIL expr { $$ = new RepeatNode($4, $2); } + ; + + %% diff --git a/Module8/Visitors/AutoVisitor.cs b/Module8/Visitors/AutoVisitor.cs index 5d50877..23010f4 100644 --- a/Module8/Visitors/AutoVisitor.cs +++ b/Module8/Visitors/AutoVisitor.cs @@ -50,5 +50,18 @@ namespace SimpleLang.Visitors cond.ifFalse.Visit(this); } } + + public override void VisitWhileNode(WhileNode whileNode) + { + whileNode.Expr.Visit(this); + whileNode.Stat.Visit(this); + } + + public override void VisitRepeatNode(RepeatNode repeatNode) + { + repeatNode.StList.Visit(this); + repeatNode.Expr.Visit(this); + } + } } diff --git a/Module8/Visitors/GenCodeVisitors/GenCodeVisitor.cs b/Module8/Visitors/GenCodeVisitors/GenCodeVisitor.cs index 88891ad..4ebe637 100644 --- a/Module8/Visitors/GenCodeVisitors/GenCodeVisitor.cs +++ b/Module8/Visitors/GenCodeVisitors/GenCodeVisitor.cs @@ -44,6 +44,10 @@ namespace SimpleLang.Visitors case '/': genc.Emit(OpCodes.Div); break; + case '%': + genc.Emit(OpCodes.Rem); + break; + } } public override void VisitAssignNode(AssignNode a) @@ -94,6 +98,55 @@ namespace SimpleLang.Visitors vars[v.Name] = genc.DeclareLocal(typeof(int)); } + public override void VisitIfNode(IfNode cond) + { + var elseLabel = genc.DefineLabel(); + cond.expr.Visit(this); + + genc.Emit(OpCodes.Ldc_I4_0); // положил 0 РЅР° стек + genc.Emit(OpCodes.Beq, elseLabel); // если if expr == 0 тогда переод Рє elseLabel + cond.ifTrue.Visit(this); + + genc.MarkLabel(elseLabel); + if (cond.ifFalse != null) + cond.ifFalse.Visit(this); + } + + public override void VisitWhileNode(WhileNode whileNode) + { + var loopLabel = genc.DefineLabel(); + var endLabel = genc.DefineLabel(); + + genc.MarkLabel(loopLabel); + + whileNode.Expr.Visit(this); + genc.Emit(OpCodes.Ldc_I4_0); // положил 0 РЅР° стек + genc.Emit(OpCodes.Beq, endLabel); // если expr == 0 тогда переход Рє endLabel + + whileNode.Stat.Visit(this); + + genc.Emit(OpCodes.Br, loopLabel); // переход Рє loopLabel + genc.MarkLabel(endLabel); + } + + public override void VisitRepeatNode(RepeatNode repeatNode) + { + var loopLabel = genc.DefineLabel(); + var endLabel = genc.DefineLabel(); + + genc.MarkLabel(loopLabel); + repeatNode.StList.Visit(this); + repeatNode.Expr.Visit(this); + + genc.Emit(OpCodes.Ldc_I4_0); + genc.Emit(OpCodes.Beq, endLabel); // если expr == 0 тогда переход Рє endLabel + genc.Emit(OpCodes.Br, loopLabel); // если expr != 0 тогда еще срабатывание + + genc.MarkLabel(endLabel); + } + + + public void EndProgram() { genc.EndProgram(); diff --git a/Module8/Visitors/Visitor.cs b/Module8/Visitors/Visitor.cs index 5fc65fc..a7b6b44 100644 --- a/Module8/Visitors/Visitor.cs +++ b/Module8/Visitors/Visitor.cs @@ -18,5 +18,8 @@ namespace SimpleLang.Visitors public virtual void VisitVarDefNode(VarDefNode w) { } public virtual void VisitEmptyNode(EmptyNode w) { } public virtual void VisitIfNode(IfNode cond) { } + + public virtual void VisitWhileNode(WhileNode whileNode) { } + public virtual void VisitRepeatNode(RepeatNode repeatNodee) { } } } diff --git a/Module8/packages.config b/Module8/packages.config new file mode 100644 index 0000000..e68db37 --- /dev/null +++ b/Module8/packages.config @@ -0,0 +1,6 @@ +п»ї<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> +</packages> \ No newline at end of file diff --git a/NunitReportParser/NunitReport.csproj b/NunitReportParser/NunitReport.csproj index 5ae8b06..373d8a1 100644 --- a/NunitReportParser/NunitReport.csproj +++ b/NunitReportParser/NunitReport.csproj @@ -1,5 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> @@ -13,6 +15,8 @@ <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <Deterministic>true</Deterministic> <TargetFrameworkProfile /> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> @@ -38,6 +42,9 @@ <HintPath>..\packages\Newtonsoft.Json.12.0.3-beta1\lib\net45\Newtonsoft.Json.dll</HintPath> <Private>True</Private> </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> @@ -56,4 +63,11 @@ <None Include="packages.config" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Данный проект ссылается РЅР° пакеты NuGet, отсутствующие РЅР° этом компьютере. Рспользуйте восстановление пакетов NuGet, чтобы скачать РёС…. Дополнительную информацию СЃРј. РїРѕ адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" /> + </Target> </Project> \ No newline at end of file diff --git a/NunitReportParser/packages.config b/NunitReportParser/packages.config index 8a038e6..8395e35 100644 --- a/NunitReportParser/packages.config +++ b/NunitReportParser/packages.config @@ -1,4 +1,7 @@ п»ї<?xml version="1.0" encoding="utf-8"?> <packages> <package id="Newtonsoft.Json" version="12.0.3-beta1" targetFramework="net461" /> + <package id="NUnit" version="3.12.0" targetFramework="net48" /> + <package id="NUnit.ConsoleRunner" version="3.10.0" targetFramework="net48" /> + <package id="NUnit3TestAdapter" version="3.15.1" targetFramework="net48" /> </packages> \ No newline at end of file diff --git a/TestASTParser/Tests.cs b/TestASTParser/Tests.cs index e5a67a2..21a2d83 100644 --- a/TestASTParser/Tests.cs +++ b/TestASTParser/Tests.cs @@ -58,7 +58,9 @@ namespace TestASTParser { var tree = ASTParserTests.Parse("begin repeat a:=2 until 2 end"); Assert.AreEqual("ProgramTree.RepeatNode, SimpleLang", (string)tree["StList"]["$values"][0]["$type"]); - // TODO: проверить узлы содержимого repeat + Assert.AreEqual("ProgramTree.IntNumNode, SimpleLang", (string)tree["StList"]["$values"][0]["Expr"]["$type"]); + Assert.AreEqual("2", ((string)tree["StList"]["$values"][0]["Expr"]["Num"]).Trim()); + } } @@ -71,12 +73,12 @@ namespace TestASTParser { var tree = ASTParserTests.Parse("begin for i:=2 to 10 do a:=2 end"); Assert.AreEqual("ProgramTree.ForNode, SimpleLang", (string)tree["StList"]["$values"][0]["$type"]); - // TODO: проверить узлы содержимого for + Assert.AreEqual("2", ((string)tree["StList"]["$values"][0]["Assign"]["Expr"]["Num"]).Trim()); } } [TestFixture] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class WriteTests { @@ -85,7 +87,7 @@ namespace TestASTParser { var tree = ASTParserTests.Parse("begin write(2) end"); Assert.AreEqual("ProgramTree.WriteNode, SimpleLang", (string)tree["StList"]["$values"][0]["$type"]); - // TODO: проверить содержимое write + Assert.AreEqual("2", ((string)tree["StList"]["$values"][0]["Expr"]["Num"]).Trim()); } } @@ -94,26 +96,42 @@ namespace TestASTParser { [Test] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public void TestIf() { - Assert.Fail(); - // TODO: дописать тест + var tree = ASTParserTests.Parse("begin if 2 then a:=12; if 5 then b:=666 else b:=777 end"); + Assert.AreEqual("ProgramTree.IfNode, SimpleLang", (string)tree["StList"]["$values"][0]["$type"]); + Assert.AreEqual("ProgramTree.IntNumNode, SimpleLang", (string)tree["StList"]["$values"][0]["Expr"]["$type"]); + + Assert.AreEqual("2", ((string)tree["StList"]["$values"][0]["Expr"]["Num"]).Trim()); + Assert.AreEqual("ProgramTree.AssignNode, SimpleLang", (string)tree["StList"]["$values"][0]["IfStat"]["$type"]); + } - + [Test] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public void TestVarDef() { - Assert.Fail(); - // TODO: дописать тест + var tree = ASTParserTests.Parse(@"begin var a,b,c end"); + Assert.AreEqual("ProgramTree.VarNode, SimpleLang", (string)tree["StList"]["$values"][0]["$type"]); + Assert.AreEqual("ProgramTree.IdNode, SimpleLang", (string)tree["StList"]["$values"][0]["IDList"]["$values"][0]["$type"]); + + Assert.AreEqual("a", (string)tree["StList"]["$values"][0]["IDList"]["$values"][0]["Name"]); + Assert.AreEqual("b", (string)tree["StList"]["$values"][0]["IDList"]["$values"][1]["Name"]); + } - + [Test] public void TestBinary() { - Assert.Fail(); - // TODO: дописать тест + var tree = ASTParserTests.Parse("begin x:=y*z+1/(1-y) end"); + + Assert.AreEqual("ProgramTree.BinNode, SimpleLang", (string)tree["StList"]["$values"][0]["Expr"]["Right"]["$type"]); + Assert.AreEqual("1", ((string)tree["StList"]["$values"][0]["Expr"]["Right"]["Left"]["Num"]).Trim()); + Assert.AreEqual(ProgramTree.BinOpType.SUB, ((ProgramTree.BinOpType)(int)tree["StList"]["$values"][0]["Expr"]["Right"]["Right"]["Operation"])); + Assert.AreEqual("1", ((string)tree["StList"]["$values"][0]["Expr"]["Right"]["Right"]["Left"]["Num"]).Trim()); + Assert.AreEqual("y", ((string)tree["StList"]["$values"][0]["Expr"]["Right"]["Right"]["Right"]["Name"]).Trim()); + } } } \ No newline at end of file diff --git a/TestCodeGenerator/Tests.cs b/TestCodeGenerator/Tests.cs index c8f33a0..cb30d77 100644 --- a/TestCodeGenerator/Tests.cs +++ b/TestCodeGenerator/Tests.cs @@ -79,7 +79,7 @@ namespace TestCodeGenerator public void TestIf() { Assert.AreEqual("3", TestHelper.GenerateNRun(@"begin var a1; a1 := 0; if a1 then write(2) else write(3) end")); - + Assert.AreEqual("3", TestHelper.GenerateNRun(@"begin var x,y; x := 1; y := x-1; if x then if y then write(2) else write(3) end")); } diff --git a/TestDescentParser/Tests.cs b/TestDescentParser/Tests.cs index 2d3de16..e523ebd 100644 --- a/TestDescentParser/Tests.cs +++ b/TestDescentParser/Tests.cs @@ -26,7 +26,7 @@ namespace TestDescentParser } [Test] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public void TestWhile() { Assert.IsTrue(Parse(@"begin while 5 do a:=2 end")); @@ -75,7 +75,7 @@ namespace TestDescentParser } [Test] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public void TestIf() { Assert.IsTrue(Parse(@"begin @@ -101,7 +101,7 @@ namespace TestDescentParser } [Test] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public void TestExpr() { Assert.IsTrue(Parse(@"begin diff --git a/TestGeneratedLexer/Tests.cs b/TestGeneratedLexer/Tests.cs index 57d7d4c..1bd6906 100644 --- a/TestGeneratedLexer/Tests.cs +++ b/TestGeneratedLexer/Tests.cs @@ -40,17 +40,17 @@ namespace TestGeneratedLexer } [Test] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public void TestString() { LexerAddon lexer = new LexerAddon(@"3 389 3 'ssfsf ' "); lexer.Lex(); - - // TODO: checks in this test + + Assert.AreEqual("'ssfsf '", lexer.apostrophe); } [Test] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public void TestSingleLineCmt() { LexerAddon lexer = new LexerAddon(@"i22d1 5.6 // i 32 id3 @@ -63,7 +63,7 @@ namespace TestGeneratedLexer } [Test] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public void TestMultiLineCmt() { LexerAddon lexer = new LexerAddon(@"i22d1 5.6 { i 32 id3 @@ -76,7 +76,7 @@ namespace TestGeneratedLexer } [Test] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public void TestMultiLineCmtIds() { LexerAddon lexer = new LexerAddon(@"i22d1 5.6 { i 32 id3 diff --git a/TestLexer/Tests.cs b/TestLexer/Tests.cs index face58f..81ee1ac 100644 --- a/TestLexer/Tests.cs +++ b/TestLexer/Tests.cs @@ -1,5 +1,6 @@ -using Lexer; +using System; using NUnit.Framework; +using Lexer; namespace TestLexer { @@ -459,7 +460,7 @@ namespace TestLexer } [TestFixture] - // [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class TestCommentLexer { @@ -493,7 +494,7 @@ namespace TestLexer } } - + //[Ignore("This test is disabled")] [TestFixture] public class TestIdChainLexer @@ -503,35 +504,35 @@ namespace TestLexer { IdentChainLexer l = new IdentChainLexer("Id1"); Assert.IsTrue(l.Parse(), "РќРµ пропускает Id1"); - + l = new IdentChainLexer("Id1.Id2"); Assert.IsTrue(l.Parse(), "РќРµ пропускает Id1.Id2"); - + l = new IdentChainLexer("uUd.k_22.sa3"); Assert.IsTrue(l.Parse(), "РќРµ пропускает uUd.k_22.sa3"); } - + [Test] public void TestIdChainFail() { IdentChainLexer l = new IdentChainLexer("3Id1"); Assert.Throws<LexerException>(() => { l.Parse(); }, "Пропускает 3Id1"); - + l = new IdentChainLexer(".Id2"); Assert.Throws<LexerException>(() => { l.Parse(); }, "Пропускает .Id2"); - + l = new IdentChainLexer("uUd."); Assert.Throws<LexerException>(() => { l.Parse(); }, "Пропускает uUd."); - + l = new IdentChainLexer("uUd.3sa"); Assert.Throws<LexerException>(() => { l.Parse(); }, "Пропускает uUd.3sa"); - + l = new IdentChainLexer("uUd. _sa"); Assert.Throws<LexerException>(() => { l.Parse(); }, "Пропускает uUd. _sa"); - + l = new IdentChainLexer("uUd,sa"); Assert.Throws<LexerException>(() => { l.Parse(); }, "Пропускает uUd,sa"); - + } } } \ No newline at end of file diff --git a/TestSimpleLexer/Tests.cs b/TestSimpleLexer/Tests.cs index 1416597..ea8d836 100644 --- a/TestSimpleLexer/Tests.cs +++ b/TestSimpleLexer/Tests.cs @@ -19,7 +19,7 @@ namespace TestSimpleLexer } [TestFixture] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class TestSimpleLexer { public static List< KeyValuePair<Tok, string> > getLexerOutput(Lexer l) @@ -56,7 +56,7 @@ namespace TestSimpleLexer } [TestFixture] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class TestSimpleLexerOps { [Test] @@ -126,7 +126,7 @@ namespace TestSimpleLexer } [TestFixture] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class TestSimpleLexerAssigns { [Test] @@ -218,7 +218,7 @@ namespace TestSimpleLexer } [TestFixture] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class TestSimpleLexerLineCmt { [Test] @@ -280,7 +280,7 @@ namespace TestSimpleLexer } [TestFixture] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class TestSimpleLexerMultLineCmt { [Test] diff --git a/TestVisitors/Tests.cs b/TestVisitors/Tests.cs index a5d43a5..67c5747 100644 --- a/TestVisitors/Tests.cs +++ b/TestVisitors/Tests.cs @@ -20,7 +20,7 @@ namespace TestVisitors } [TestFixture] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class TestAvgOpCount: ParserTest { [Test] @@ -69,10 +69,37 @@ namespace TestVisitors p.root.Visit(avgCounter); Assert.AreEqual(4, avgCounter.MidCount()); } + + [Test] + public void TwoLoopsWithWriteTest() + { + Parser p = Parse(@"begin + var c; + b := 2; + c := 3; + c := c * 4 + b;;; + cycle 3 + begin + c := c + 1; + write(c) + end; + cycle 3 + begin + d := 2; + write(c); + write(c); + write(c) + end + end"); + Assert.IsTrue(p.Parse()); + var avgCounter = new CountCyclesOpVisitor(); + p.root.Visit(avgCounter); + Assert.AreEqual(3, avgCounter.MidCount()); + } } [TestFixture] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class TestCommonVariable: ParserTest { [Test] @@ -97,7 +124,7 @@ namespace TestVisitors } [TestFixture] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class TestExprComplexity: ParserTest { [Test] @@ -202,7 +229,7 @@ namespace TestVisitors } [TestFixture] - [Ignore("This test is disabled")] + //[Ignore("This test is disabled")] public class TestIfCycleNest: ParserTest { [Test] -- GitLab