diff --git a/InhaCC/App.config b/InhaCC/App.config
new file mode 100644
index 0000000..b0ce3e1
--- /dev/null
+++ b/InhaCC/App.config
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/InhaCC/Graph.cs b/InhaCC/Graph.cs
new file mode 100644
index 0000000..eea2466
--- /dev/null
+++ b/InhaCC/Graph.cs
@@ -0,0 +1,51 @@
+/*
+
+ Copyright (C) 2019. rollrat All Rights Reserved.
+
+ Author: Jeong HyunJun
+
+*/
+
+using GraphVizWrapper;
+using GraphVizWrapper.Commands;
+using GraphVizWrapper.Queries;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InhaCC
+{
+ public class Graph
+ {
+ public static Bitmap ToImage(string str)
+ {
+ var getStartProcessQuery = new GetStartProcessQuery();
+ var getProcessStartInfoQuery = new GetProcessStartInfoQuery();
+ var registerLayoutPluginCommand = new RegisterLayoutPluginCommand(getProcessStartInfoQuery, getStartProcessQuery);
+
+ var wrapper = new GraphGeneration(getStartProcessQuery,
+ getProcessStartInfoQuery,
+ registerLayoutPluginCommand);
+
+ byte[] output = wrapper.GenerateGraph(str /*"digraph{a -> b; b -> c; c -> a;}"*/, Enums.GraphReturnType.Png);
+
+ return ByteToImage(output);
+ }
+
+
+ private static Bitmap ByteToImage(byte[] blob)
+ {
+ MemoryStream mStream = new MemoryStream();
+ byte[] pData = blob;
+ mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
+ Bitmap bm = new Bitmap(mStream, false);
+ mStream.Dispose();
+ return bm;
+ }
+
+ }
+}
diff --git a/InhaCC/InhaCC.csproj b/InhaCC/InhaCC.csproj
new file mode 100644
index 0000000..339900b
--- /dev/null
+++ b/InhaCC/InhaCC.csproj
@@ -0,0 +1,116 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {F608DB8C-F9F1-40C1-866F-BA348E566E64}
+ WinExe
+ InhaCC
+ InhaCC
+ v4.5
+ 512
+ true
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+
+ ..\packages\GraphViz.NET.1.0.0\lib\net40\GraphVizWrapper.dll
+
+
+
+ ..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ MainForm.cs
+
+
+
+
+ MainForm.cs
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+ True
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/InhaCC/MainForm.Designer.cs b/InhaCC/MainForm.Designer.cs
new file mode 100644
index 0000000..d982bf7
--- /dev/null
+++ b/InhaCC/MainForm.Designer.cs
@@ -0,0 +1,689 @@
+namespace InhaCC
+{
+ partial class MainForm
+ {
+ ///
+ /// 필수 디자이너 변수입니다.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// 사용 중인 모든 리소스를 정리합니다.
+ ///
+ /// 관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form 디자이너에서 생성한 코드
+
+ ///
+ /// 디자이너 지원에 필요한 메서드입니다.
+ /// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
+ ///
+ private void InitializeComponent()
+ {
+ this.tabControl1 = new System.Windows.Forms.TabControl();
+ this.tabPage1 = new System.Windows.Forms.TabPage();
+ this.bREA = new System.Windows.Forms.Button();
+ this.tbRE = new System.Windows.Forms.TextBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.tabControl2 = new System.Windows.Forms.TabControl();
+ this.tabPage7 = new System.Windows.Forms.TabPage();
+ this.panel4 = new System.Windows.Forms.Panel();
+ this.pictureBox1 = new System.Windows.Forms.PictureBox();
+ this.tabPage9 = new System.Windows.Forms.TabPage();
+ this.panel3 = new System.Windows.Forms.Panel();
+ this.pictureBox2 = new System.Windows.Forms.PictureBox();
+ this.tabPage11 = new System.Windows.Forms.TabPage();
+ this.panel2 = new System.Windows.Forms.Panel();
+ this.pictureBox3 = new System.Windows.Forms.PictureBox();
+ this.tabPage10 = new System.Windows.Forms.TabPage();
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.pictureBox4 = new System.Windows.Forms.PictureBox();
+ this.tabPage2 = new System.Windows.Forms.TabPage();
+ this.rtbLS = new System.Windows.Forms.RichTextBox();
+ this.label3 = new System.Windows.Forms.Label();
+ this.bLT = new System.Windows.Forms.Button();
+ this.rtbLT = new System.Windows.Forms.RichTextBox();
+ this.bLG = new System.Windows.Forms.Button();
+ this.rtbLLD = new System.Windows.Forms.RichTextBox();
+ this.label2 = new System.Windows.Forms.Label();
+ this.tabPage3 = new System.Windows.Forms.TabPage();
+ this.bPGG = new System.Windows.Forms.Button();
+ this.bPGT = new System.Windows.Forms.Button();
+ this.rtbPGTEST = new System.Windows.Forms.RichTextBox();
+ this.label10 = new System.Windows.Forms.Label();
+ this.rtbPGS = new System.Windows.Forms.RichTextBox();
+ this.label9 = new System.Windows.Forms.Label();
+ this.rbLR1 = new System.Windows.Forms.RadioButton();
+ this.rbLALR = new System.Windows.Forms.RadioButton();
+ this.rbSLR = new System.Windows.Forms.RadioButton();
+ this.label8 = new System.Windows.Forms.Label();
+ this.rtbPGC = new System.Windows.Forms.RichTextBox();
+ this.label7 = new System.Windows.Forms.Label();
+ this.rtbPGPR = new System.Windows.Forms.RichTextBox();
+ this.label6 = new System.Windows.Forms.Label();
+ this.rtbPGT = new System.Windows.Forms.RichTextBox();
+ this.label5 = new System.Windows.Forms.Label();
+ this.rtbPGNT = new System.Windows.Forms.RichTextBox();
+ this.label4 = new System.Windows.Forms.Label();
+ this.rbLALR0 = new System.Windows.Forms.RadioButton();
+ this.tabControl1.SuspendLayout();
+ this.tabPage1.SuspendLayout();
+ this.tabControl2.SuspendLayout();
+ this.tabPage7.SuspendLayout();
+ this.panel4.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+ this.tabPage9.SuspendLayout();
+ this.panel3.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
+ this.tabPage11.SuspendLayout();
+ this.panel2.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).BeginInit();
+ this.tabPage10.SuspendLayout();
+ this.panel1.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox4)).BeginInit();
+ this.tabPage2.SuspendLayout();
+ this.tabPage3.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // tabControl1
+ //
+ this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tabControl1.Controls.Add(this.tabPage1);
+ this.tabControl1.Controls.Add(this.tabPage2);
+ this.tabControl1.Controls.Add(this.tabPage3);
+ this.tabControl1.Location = new System.Drawing.Point(12, 12);
+ this.tabControl1.Name = "tabControl1";
+ this.tabControl1.SelectedIndex = 0;
+ this.tabControl1.Size = new System.Drawing.Size(1391, 743);
+ this.tabControl1.TabIndex = 0;
+ //
+ // tabPage1
+ //
+ this.tabPage1.Controls.Add(this.bREA);
+ this.tabPage1.Controls.Add(this.tbRE);
+ this.tabPage1.Controls.Add(this.label1);
+ this.tabPage1.Controls.Add(this.tabControl2);
+ this.tabPage1.Location = new System.Drawing.Point(4, 24);
+ this.tabPage1.Name = "tabPage1";
+ this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
+ this.tabPage1.Size = new System.Drawing.Size(1383, 715);
+ this.tabPage1.TabIndex = 0;
+ this.tabPage1.Text = "Regular Expression";
+ this.tabPage1.UseVisualStyleBackColor = true;
+ //
+ // bREA
+ //
+ this.bREA.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.bREA.Location = new System.Drawing.Point(1261, 20);
+ this.bREA.Name = "bREA";
+ this.bREA.Size = new System.Drawing.Size(85, 23);
+ this.bREA.TabIndex = 5;
+ this.bREA.Text = "Apply";
+ this.bREA.UseVisualStyleBackColor = true;
+ this.bREA.Click += new System.EventHandler(this.bREA_Click);
+ //
+ // tbRE
+ //
+ this.tbRE.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbRE.Font = new System.Drawing.Font("Consolas", 9F);
+ this.tbRE.Location = new System.Drawing.Point(76, 21);
+ this.tbRE.Name = "tbRE";
+ this.tbRE.Size = new System.Drawing.Size(1179, 22);
+ this.tbRE.TabIndex = 4;
+ this.tbRE.Text = "[0-9]+(\\.[0-9]+)?[Ee][\\+\\-]?[0-9]+";
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(18, 24);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(52, 15);
+ this.label1.TabIndex = 3;
+ this.label1.Text = "Pattern: ";
+ //
+ // tabControl2
+ //
+ this.tabControl2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tabControl2.Controls.Add(this.tabPage7);
+ this.tabControl2.Controls.Add(this.tabPage9);
+ this.tabControl2.Controls.Add(this.tabPage11);
+ this.tabControl2.Controls.Add(this.tabPage10);
+ this.tabControl2.Location = new System.Drawing.Point(6, 60);
+ this.tabControl2.Name = "tabControl2";
+ this.tabControl2.SelectedIndex = 0;
+ this.tabControl2.Size = new System.Drawing.Size(1374, 649);
+ this.tabControl2.TabIndex = 0;
+ //
+ // tabPage7
+ //
+ this.tabPage7.Controls.Add(this.panel4);
+ this.tabPage7.Location = new System.Drawing.Point(4, 24);
+ this.tabPage7.Name = "tabPage7";
+ this.tabPage7.Padding = new System.Windows.Forms.Padding(3);
+ this.tabPage7.Size = new System.Drawing.Size(1366, 621);
+ this.tabPage7.TabIndex = 5;
+ this.tabPage7.Text = "NFA";
+ this.tabPage7.UseVisualStyleBackColor = true;
+ //
+ // panel4
+ //
+ this.panel4.AutoScroll = true;
+ this.panel4.Controls.Add(this.pictureBox1);
+ this.panel4.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.panel4.Location = new System.Drawing.Point(3, 3);
+ this.panel4.Name = "panel4";
+ this.panel4.Size = new System.Drawing.Size(1360, 615);
+ this.panel4.TabIndex = 4;
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.Location = new System.Drawing.Point(3, 3);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.Size = new System.Drawing.Size(1067, 409);
+ this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+ this.pictureBox1.TabIndex = 2;
+ this.pictureBox1.TabStop = false;
+ //
+ // tabPage9
+ //
+ this.tabPage9.Controls.Add(this.panel3);
+ this.tabPage9.Location = new System.Drawing.Point(4, 24);
+ this.tabPage9.Name = "tabPage9";
+ this.tabPage9.Size = new System.Drawing.Size(1366, 621);
+ this.tabPage9.TabIndex = 1;
+ this.tabPage9.Text = "e-NFA";
+ this.tabPage9.UseVisualStyleBackColor = true;
+ //
+ // panel3
+ //
+ this.panel3.AutoScroll = true;
+ this.panel3.Controls.Add(this.pictureBox2);
+ this.panel3.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.panel3.Location = new System.Drawing.Point(0, 0);
+ this.panel3.Name = "panel3";
+ this.panel3.Size = new System.Drawing.Size(1366, 621);
+ this.panel3.TabIndex = 4;
+ //
+ // pictureBox2
+ //
+ this.pictureBox2.Location = new System.Drawing.Point(3, 3);
+ this.pictureBox2.Name = "pictureBox2";
+ this.pictureBox2.Size = new System.Drawing.Size(1067, 409);
+ this.pictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+ this.pictureBox2.TabIndex = 2;
+ this.pictureBox2.TabStop = false;
+ //
+ // tabPage11
+ //
+ this.tabPage11.Controls.Add(this.panel2);
+ this.tabPage11.Location = new System.Drawing.Point(4, 24);
+ this.tabPage11.Name = "tabPage11";
+ this.tabPage11.Size = new System.Drawing.Size(1366, 621);
+ this.tabPage11.TabIndex = 3;
+ this.tabPage11.Text = "DFA";
+ this.tabPage11.UseVisualStyleBackColor = true;
+ //
+ // panel2
+ //
+ this.panel2.AutoScroll = true;
+ this.panel2.Controls.Add(this.pictureBox3);
+ this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.panel2.Location = new System.Drawing.Point(0, 0);
+ this.panel2.Name = "panel2";
+ this.panel2.Size = new System.Drawing.Size(1366, 621);
+ this.panel2.TabIndex = 4;
+ //
+ // pictureBox3
+ //
+ this.pictureBox3.Location = new System.Drawing.Point(3, 3);
+ this.pictureBox3.Name = "pictureBox3";
+ this.pictureBox3.Size = new System.Drawing.Size(1067, 409);
+ this.pictureBox3.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+ this.pictureBox3.TabIndex = 2;
+ this.pictureBox3.TabStop = false;
+ //
+ // tabPage10
+ //
+ this.tabPage10.Controls.Add(this.panel1);
+ this.tabPage10.Location = new System.Drawing.Point(4, 24);
+ this.tabPage10.Name = "tabPage10";
+ this.tabPage10.Size = new System.Drawing.Size(1366, 621);
+ this.tabPage10.TabIndex = 4;
+ this.tabPage10.Text = "DFA Minimization";
+ this.tabPage10.UseVisualStyleBackColor = true;
+ //
+ // panel1
+ //
+ this.panel1.AutoScroll = true;
+ this.panel1.Controls.Add(this.pictureBox4);
+ this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.panel1.Location = new System.Drawing.Point(0, 0);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(1366, 621);
+ this.panel1.TabIndex = 3;
+ //
+ // pictureBox4
+ //
+ this.pictureBox4.Location = new System.Drawing.Point(3, 3);
+ this.pictureBox4.Name = "pictureBox4";
+ this.pictureBox4.Size = new System.Drawing.Size(1067, 409);
+ this.pictureBox4.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+ this.pictureBox4.TabIndex = 2;
+ this.pictureBox4.TabStop = false;
+ //
+ // tabPage2
+ //
+ this.tabPage2.Controls.Add(this.rtbLS);
+ this.tabPage2.Controls.Add(this.label3);
+ this.tabPage2.Controls.Add(this.bLT);
+ this.tabPage2.Controls.Add(this.rtbLT);
+ this.tabPage2.Controls.Add(this.bLG);
+ this.tabPage2.Controls.Add(this.rtbLLD);
+ this.tabPage2.Controls.Add(this.label2);
+ this.tabPage2.Location = new System.Drawing.Point(4, 24);
+ this.tabPage2.Name = "tabPage2";
+ this.tabPage2.Size = new System.Drawing.Size(1383, 715);
+ this.tabPage2.TabIndex = 1;
+ this.tabPage2.Text = "Lexer Generator";
+ this.tabPage2.UseVisualStyleBackColor = true;
+ //
+ // rtbLS
+ //
+ this.rtbLS.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.rtbLS.Font = new System.Drawing.Font("Consolas", 9F);
+ this.rtbLS.Location = new System.Drawing.Point(404, 35);
+ this.rtbLS.Name = "rtbLS";
+ this.rtbLS.Size = new System.Drawing.Size(943, 618);
+ this.rtbLS.TabIndex = 6;
+ this.rtbLS.Text = "";
+ this.rtbLS.TextChanged += new System.EventHandler(this.rtbLS_TextChanged);
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(401, 17);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(43, 15);
+ this.label3.TabIndex = 5;
+ this.label3.Text = "Status:";
+ //
+ // bLT
+ //
+ this.bLT.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.bLT.Location = new System.Drawing.Point(99, 659);
+ this.bLT.Name = "bLT";
+ this.bLT.Size = new System.Drawing.Size(231, 34);
+ this.bLT.TabIndex = 4;
+ this.bLT.Text = "Test!";
+ this.bLT.UseVisualStyleBackColor = true;
+ this.bLT.Click += new System.EventHandler(this.bLT_Click);
+ //
+ // rtbLT
+ //
+ this.rtbLT.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.rtbLT.Font = new System.Drawing.Font("Consolas", 9F);
+ this.rtbLT.Location = new System.Drawing.Point(31, 475);
+ this.rtbLT.Name = "rtbLT";
+ this.rtbLT.Size = new System.Drawing.Size(367, 178);
+ this.rtbLT.TabIndex = 3;
+ this.rtbLT.Text = "2-(3+5);\n2 + (6 * 3);\n(3 + 2)*2 + 5;\n2.0E-2+0.5;\n5+10\n";
+ //
+ // bLG
+ //
+ this.bLG.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.bLG.Location = new System.Drawing.Point(99, 435);
+ this.bLG.Name = "bLG";
+ this.bLG.Size = new System.Drawing.Size(231, 34);
+ this.bLG.TabIndex = 2;
+ this.bLG.Text = "Generate!";
+ this.bLG.UseVisualStyleBackColor = true;
+ this.bLG.Click += new System.EventHandler(this.bLG_Click);
+ //
+ // rtbLLD
+ //
+ this.rtbLLD.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)));
+ this.rtbLLD.Font = new System.Drawing.Font("Consolas", 9F);
+ this.rtbLLD.Location = new System.Drawing.Point(31, 35);
+ this.rtbLLD.Name = "rtbLLD";
+ this.rtbLLD.Size = new System.Drawing.Size(367, 394);
+ this.rtbLLD.TabIndex = 1;
+ this.rtbLLD.Text = "[\\r\\n ] => \"\"\n; => end\n\\+ => plus\n- => minus\n\\* => multiple\n\\/ => divide\n\\( => op" +
+ "_open\n\\) => op_close\n[_$a-zA-Z][_$a-zA-Z0-9]* => id\n[0-9]+(\\.[0-9]+)?[Ee][\\+\\-]?" +
+ "[0-9]+ => num\n[0-9]+(\\.[0-9]+)? => num";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(28, 17);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(99, 15);
+ this.label2.TabIndex = 0;
+ this.label2.Text = "Lexer Definition: ";
+ //
+ // tabPage3
+ //
+ this.tabPage3.Controls.Add(this.rbLALR0);
+ this.tabPage3.Controls.Add(this.bPGG);
+ this.tabPage3.Controls.Add(this.bPGT);
+ this.tabPage3.Controls.Add(this.rtbPGTEST);
+ this.tabPage3.Controls.Add(this.label10);
+ this.tabPage3.Controls.Add(this.rtbPGS);
+ this.tabPage3.Controls.Add(this.label9);
+ this.tabPage3.Controls.Add(this.rbLR1);
+ this.tabPage3.Controls.Add(this.rbLALR);
+ this.tabPage3.Controls.Add(this.rbSLR);
+ this.tabPage3.Controls.Add(this.label8);
+ this.tabPage3.Controls.Add(this.rtbPGC);
+ this.tabPage3.Controls.Add(this.label7);
+ this.tabPage3.Controls.Add(this.rtbPGPR);
+ this.tabPage3.Controls.Add(this.label6);
+ this.tabPage3.Controls.Add(this.rtbPGT);
+ this.tabPage3.Controls.Add(this.label5);
+ this.tabPage3.Controls.Add(this.rtbPGNT);
+ this.tabPage3.Controls.Add(this.label4);
+ this.tabPage3.Location = new System.Drawing.Point(4, 24);
+ this.tabPage3.Name = "tabPage3";
+ this.tabPage3.Size = new System.Drawing.Size(1383, 715);
+ this.tabPage3.TabIndex = 2;
+ this.tabPage3.Text = "Parser Generator";
+ this.tabPage3.UseVisualStyleBackColor = true;
+ //
+ // bPGG
+ //
+ this.bPGG.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.bPGG.Location = new System.Drawing.Point(293, 660);
+ this.bPGG.Name = "bPGG";
+ this.bPGG.Size = new System.Drawing.Size(99, 26);
+ this.bPGG.TabIndex = 19;
+ this.bPGG.Text = "Generate";
+ this.bPGG.UseVisualStyleBackColor = true;
+ this.bPGG.Click += new System.EventHandler(this.bPGG_Click);
+ //
+ // bPGT
+ //
+ this.bPGT.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.bPGT.Location = new System.Drawing.Point(1250, 660);
+ this.bPGT.Name = "bPGT";
+ this.bPGT.Size = new System.Drawing.Size(99, 26);
+ this.bPGT.TabIndex = 18;
+ this.bPGT.Text = "Test";
+ this.bPGT.UseVisualStyleBackColor = true;
+ this.bPGT.Click += new System.EventHandler(this.bPGT_Click);
+ //
+ // rtbPGTEST
+ //
+ this.rtbPGTEST.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.rtbPGTEST.Font = new System.Drawing.Font("Consolas", 9F);
+ this.rtbPGTEST.Location = new System.Drawing.Point(293, 530);
+ this.rtbPGTEST.Name = "rtbPGTEST";
+ this.rtbPGTEST.Size = new System.Drawing.Size(1056, 124);
+ this.rtbPGTEST.TabIndex = 17;
+ this.rtbPGTEST.Text = "2-(3+5);\n2 + (6 * 3);\n(3 + 2)*2 + 5;\n2.0E-2+0.5;\n5+10";
+ //
+ // label10
+ //
+ this.label10.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.label10.AutoSize = true;
+ this.label10.Location = new System.Drawing.Point(290, 512);
+ this.label10.Name = "label10";
+ this.label10.Size = new System.Drawing.Size(35, 15);
+ this.label10.TabIndex = 16;
+ this.label10.Text = "Test: ";
+ //
+ // rtbPGS
+ //
+ this.rtbPGS.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.rtbPGS.Font = new System.Drawing.Font("Consolas", 9F);
+ this.rtbPGS.Location = new System.Drawing.Point(293, 51);
+ this.rtbPGS.Name = "rtbPGS";
+ this.rtbPGS.Size = new System.Drawing.Size(1056, 458);
+ this.rtbPGS.TabIndex = 15;
+ this.rtbPGS.Text = "";
+ this.rtbPGS.TextChanged += new System.EventHandler(this.rtbPGS_TextChanged);
+ //
+ // label9
+ //
+ this.label9.AutoSize = true;
+ this.label9.Location = new System.Drawing.Point(290, 33);
+ this.label9.Name = "label9";
+ this.label9.Size = new System.Drawing.Size(43, 15);
+ this.label9.TabIndex = 14;
+ this.label9.Text = "Status:";
+ //
+ // rbLR1
+ //
+ this.rbLR1.AutoSize = true;
+ this.rbLR1.Location = new System.Drawing.Point(662, 16);
+ this.rbLR1.Name = "rbLR1";
+ this.rbLR1.Size = new System.Drawing.Size(53, 19);
+ this.rbLR1.TabIndex = 13;
+ this.rbLR1.Text = "LR(1)";
+ this.rbLR1.UseVisualStyleBackColor = true;
+ //
+ // rbLALR
+ //
+ this.rbLALR.AutoSize = true;
+ this.rbLALR.Checked = true;
+ this.rbLALR.Location = new System.Drawing.Point(542, 16);
+ this.rbLALR.Name = "rbLALR";
+ this.rbLALR.Size = new System.Drawing.Size(114, 19);
+ this.rbLALR.TabIndex = 12;
+ this.rbLALR.Text = "LALR from LR(1)";
+ this.rbLALR.UseVisualStyleBackColor = true;
+ //
+ // rbSLR
+ //
+ this.rbSLR.AutoSize = true;
+ this.rbSLR.Location = new System.Drawing.Point(371, 16);
+ this.rbSLR.Name = "rbSLR";
+ this.rbSLR.Size = new System.Drawing.Size(45, 19);
+ this.rbSLR.TabIndex = 11;
+ this.rbSLR.Text = "SLR";
+ this.rbSLR.UseVisualStyleBackColor = true;
+ //
+ // label8
+ //
+ this.label8.AutoSize = true;
+ this.label8.Location = new System.Drawing.Point(290, 18);
+ this.label8.Name = "label8";
+ this.label8.Size = new System.Drawing.Size(75, 15);
+ this.label8.TabIndex = 10;
+ this.label8.Text = "Parser Type: ";
+ //
+ // rtbPGC
+ //
+ this.rtbPGC.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.rtbPGC.Font = new System.Drawing.Font("Consolas", 9F);
+ this.rtbPGC.Location = new System.Drawing.Point(26, 609);
+ this.rtbPGC.Name = "rtbPGC";
+ this.rtbPGC.Size = new System.Drawing.Size(258, 77);
+ this.rtbPGC.TabIndex = 9;
+ this.rtbPGC.Text = "%left +, -\n%left *, /\n%right UMINUS";
+ //
+ // label7
+ //
+ this.label7.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.label7.AutoSize = true;
+ this.label7.Location = new System.Drawing.Point(23, 591);
+ this.label7.Name = "label7";
+ this.label7.Size = new System.Drawing.Size(57, 15);
+ this.label7.TabIndex = 8;
+ this.label7.Text = "Conflicts:";
+ //
+ // rtbPGPR
+ //
+ this.rtbPGPR.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)));
+ this.rtbPGPR.Font = new System.Drawing.Font("Consolas", 9F);
+ this.rtbPGPR.Location = new System.Drawing.Point(26, 219);
+ this.rtbPGPR.Name = "rtbPGPR";
+ this.rtbPGPR.Size = new System.Drawing.Size(258, 369);
+ this.rtbPGPR.TabIndex = 7;
+ this.rtbPGPR.Text = "S -> E ;\nE -> E + E\nE -> E - E\nE -> E * E\nE -> E / E\nE -> - E %prec UMINUS\nE -> " +
+ "( E )\nE -> num";
+ //
+ // label6
+ //
+ this.label6.AutoSize = true;
+ this.label6.Location = new System.Drawing.Point(23, 201);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(101, 15);
+ this.label6.TabIndex = 6;
+ this.label6.Text = "Production Rules:";
+ //
+ // rtbPGT
+ //
+ this.rtbPGT.Font = new System.Drawing.Font("Consolas", 9F);
+ this.rtbPGT.Location = new System.Drawing.Point(26, 111);
+ this.rtbPGT.Name = "rtbPGT";
+ this.rtbPGT.Size = new System.Drawing.Size(258, 87);
+ this.rtbPGT.TabIndex = 5;
+ this.rtbPGT.Text = "equal, =\nmultiple, *\ndivide, /\nplus, +\nminus, -\nnum, num\nop_open, (\nop_close, )\ne" +
+ "nd, ;";
+ //
+ // label5
+ //
+ this.label5.AutoSize = true;
+ this.label5.Location = new System.Drawing.Point(23, 93);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(65, 15);
+ this.label5.TabIndex = 4;
+ this.label5.Text = "Terminals: ";
+ //
+ // rtbPGNT
+ //
+ this.rtbPGNT.Font = new System.Drawing.Font("Consolas", 9F);
+ this.rtbPGNT.Location = new System.Drawing.Point(26, 36);
+ this.rtbPGNT.Name = "rtbPGNT";
+ this.rtbPGNT.Size = new System.Drawing.Size(258, 52);
+ this.rtbPGNT.TabIndex = 3;
+ this.rtbPGNT.Text = "S, E";
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.Location = new System.Drawing.Point(23, 18);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(91, 15);
+ this.label4.TabIndex = 2;
+ this.label4.Text = "Non-terminals: ";
+ //
+ // rbLALR0
+ //
+ this.rbLALR0.AutoSize = true;
+ this.rbLALR0.Location = new System.Drawing.Point(422, 16);
+ this.rbLALR0.Name = "rbLALR0";
+ this.rbLALR0.Size = new System.Drawing.Size(114, 19);
+ this.rbLALR0.TabIndex = 20;
+ this.rbLALR0.Text = "LALR from LR(0)";
+ this.rbLALR0.UseVisualStyleBackColor = true;
+ //
+ // MainForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(1415, 767);
+ this.Controls.Add(this.tabControl1);
+ this.Font = new System.Drawing.Font("맑은 고딕", 9F);
+ this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
+ this.Name = "MainForm";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "InhaCC GUI - Compiler Compiler Collection";
+ this.tabControl1.ResumeLayout(false);
+ this.tabPage1.ResumeLayout(false);
+ this.tabPage1.PerformLayout();
+ this.tabControl2.ResumeLayout(false);
+ this.tabPage7.ResumeLayout(false);
+ this.panel4.ResumeLayout(false);
+ this.panel4.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+ this.tabPage9.ResumeLayout(false);
+ this.panel3.ResumeLayout(false);
+ this.panel3.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
+ this.tabPage11.ResumeLayout(false);
+ this.panel2.ResumeLayout(false);
+ this.panel2.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).EndInit();
+ this.tabPage10.ResumeLayout(false);
+ this.panel1.ResumeLayout(false);
+ this.panel1.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox4)).EndInit();
+ this.tabPage2.ResumeLayout(false);
+ this.tabPage2.PerformLayout();
+ this.tabPage3.ResumeLayout(false);
+ this.tabPage3.PerformLayout();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TabControl tabControl1;
+ private System.Windows.Forms.TabPage tabPage1;
+ private System.Windows.Forms.TabPage tabPage2;
+ private System.Windows.Forms.TabPage tabPage3;
+ private System.Windows.Forms.TabControl tabControl2;
+ private System.Windows.Forms.TabPage tabPage9;
+ private System.Windows.Forms.TabPage tabPage11;
+ private System.Windows.Forms.Button bREA;
+ private System.Windows.Forms.TextBox tbRE;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.TabPage tabPage10;
+ private System.Windows.Forms.TabPage tabPage7;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.RichTextBox rtbLLD;
+ private System.Windows.Forms.Button bLG;
+ private System.Windows.Forms.RichTextBox rtbLT;
+ private System.Windows.Forms.Button bLT;
+ private System.Windows.Forms.RichTextBox rtbLS;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.RichTextBox rtbPGT;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.RichTextBox rtbPGNT;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.RichTextBox rtbPGPR;
+ private System.Windows.Forms.Label label7;
+ private System.Windows.Forms.RichTextBox rtbPGC;
+ private System.Windows.Forms.Label label8;
+ private System.Windows.Forms.RadioButton rbLR1;
+ private System.Windows.Forms.RadioButton rbLALR;
+ private System.Windows.Forms.RadioButton rbSLR;
+ private System.Windows.Forms.RichTextBox rtbPGTEST;
+ private System.Windows.Forms.Label label10;
+ private System.Windows.Forms.RichTextBox rtbPGS;
+ private System.Windows.Forms.Label label9;
+ private System.Windows.Forms.Button bPGT;
+ private System.Windows.Forms.Button bPGG;
+ private System.Windows.Forms.PictureBox pictureBox4;
+ private System.Windows.Forms.Panel panel4;
+ private System.Windows.Forms.PictureBox pictureBox1;
+ private System.Windows.Forms.Panel panel3;
+ private System.Windows.Forms.PictureBox pictureBox2;
+ private System.Windows.Forms.Panel panel2;
+ private System.Windows.Forms.PictureBox pictureBox3;
+ private System.Windows.Forms.Panel panel1;
+ private System.Windows.Forms.RadioButton rbLALR0;
+ }
+}
+
diff --git a/InhaCC/MainForm.cs b/InhaCC/MainForm.cs
new file mode 100644
index 0000000..35df9ba
--- /dev/null
+++ b/InhaCC/MainForm.cs
@@ -0,0 +1,294 @@
+/*
+
+ Copyright (C) 2019. rollrat All Rights Reserved.
+
+ Author: Jeong HyunJun
+
+*/
+
+using GraphVizWrapper;
+using GraphVizWrapper.Commands;
+using GraphVizWrapper.Queries;
+using ParserGenerator;
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace InhaCC
+{
+ public partial class MainForm : Form
+ {
+ public MainForm()
+ {
+ InitializeComponent();
+ }
+
+ private void bREA_Click(object sender, EventArgs e)
+ {
+ var sr = new SimpleRegex();
+ sr.MakeNFA(tbRE.Text);
+ pictureBox1.Image = Graph.ToImage(SimpleRegex.PrintGraph(sr.Diagram));
+ sr.OptimizeNFA();
+ pictureBox2.Image = Graph.ToImage(SimpleRegex.PrintGraph(sr.Diagram));
+ sr.NFAtoDFA();
+ pictureBox3.Image = Graph.ToImage(SimpleRegex.PrintGraph(sr.Diagram));
+ sr.MinimizeDFA();
+ pictureBox4.Image = Graph.ToImage(SimpleRegex.PrintGraph(sr.Diagram));
+ }
+
+ Scanner scanner;
+
+ private void bLG_Click(object sender, EventArgs e)
+ {
+ var sg = new ScannerGenerator();
+
+ try
+ {
+ foreach (var line in rtbLLD.Lines)
+ sg.PushRule(line.Split(new[] { "=>" }, StringSplitOptions.None)[1].Replace("\"", "").Trim(), line.Split(new[] { "=>" }, StringSplitOptions.None)[0].Trim());
+ sg.Generate();
+ scanner = sg.CreateScannerInstance();
+ rtbLS.AppendText("New scanner instance generated!\r\n" + sg.PrintDiagram());
+ }
+ catch (Exception ex)
+ {
+ rtbLS.Text = $"Scanner build error!\r\n{ex.Message}\r\n{ex.StackTrace}";
+ }
+ }
+
+ private void bLT_Click(object sender, EventArgs e)
+ {
+ if (scanner == null)
+ {
+ rtbLS.AppendText("Create scanner instance before testing!\r\n");
+ return;
+ }
+
+ rtbLS.AppendText(" ----------- Start Lexing -----------\r\n");
+ scanner.AllocateTarget(rtbLT.Text);
+
+ try
+ {
+ while (scanner.Valid())
+ {
+ var ss = scanner.Next();
+ if (scanner.Error())
+ rtbLS.AppendText("Error!\r\n");
+ rtbLS.AppendText($"{ss.Item1},".PadRight(10) + $" {ss.Item2} - line:{ss.Item3}, column:{ss.Item4}\r\n");
+ }
+ }
+ catch (Exception ex)
+ {
+ rtbLS.AppendText("Error!\r\nCheck test case!\r\n");
+ }
+ rtbLS.AppendText(" ------------ End Lexing ------------\r\n");
+ }
+
+ private void rtbLS_TextChanged(object sender, EventArgs e)
+ {
+ rtbLS.SelectionStart = rtbLS.Text.Length;
+ rtbLS.ScrollToCaret();
+ }
+
+ ShiftReduceParser srparser;
+
+ private void bPGG_Click(object sender, EventArgs e)
+ {
+ var gen = new ParserGenerator.ParserGenerator();
+
+ try
+ {
+ var non_terminals = new Dictionary();
+ var terminals = new Dictionary();
+
+ terminals.Add("''", ParserGenerator.ParserGenerator.EmptyString);
+
+ foreach (var nt in rtbPGNT.Text.Split(','))
+ non_terminals.Add(nt.Trim(), gen.CreateNewProduction(nt.Trim(), false));
+
+ foreach (var t in rtbPGT.Lines)
+ {
+ if (t.Trim() == "") continue;
+
+ var name = t.Split(',')[0];
+ var pp = t.Substring(name.Length + 1).Trim();
+
+ terminals.Add(pp, gen.CreateNewProduction(name.Trim()));
+ }
+
+ var prec = new Dictionary>>();
+
+ foreach (var pp in rtbPGPR.Lines)
+ {
+ if (pp.Trim() == "") continue;
+
+ var split = pp.Split(new[] { "->" }, StringSplitOptions.None);
+ var left = split[0].Trim();
+ var right = split[1].Split(' ');
+
+ var prlist = new List();
+ bool stay_prec = false;
+ foreach (var ntt in right)
+ {
+ if (string.IsNullOrEmpty(ntt)) continue;
+ if (ntt == "%prec") { stay_prec = true; continue; }
+ if (stay_prec)
+ {
+ if (!prec.ContainsKey(ntt))
+ prec.Add(ntt, new List>());
+ prec[ntt].Add(new Tuple(non_terminals[left], non_terminals[left].sub_productions.Count));
+ continue;
+ }
+ if (non_terminals.ContainsKey(ntt))
+ prlist.Add(non_terminals[ntt]);
+ else if (terminals.ContainsKey(ntt))
+ prlist.Add(terminals[ntt]);
+ else
+ {
+ rtbPGS.Text = $"Production rule build error!\r\n{ntt} is neither non-terminal nor terminal!\r\nDeclare the token-name!";
+ return;
+ }
+ }
+ non_terminals[left].sub_productions.Add(prlist);
+ }
+
+ for (int i = rtbPGC.Lines.Length - 1; i >= 0; i--)
+ {
+ var line = rtbPGC.Lines[i].Trim();
+ if (line == "") continue;
+ var tt = line.Split(' ')[0];
+ var rr = line.Substring(tt.Length).Trim().Split(',');
+
+ var left = true;
+ var items1 = new List>();
+ var items2 = new List();
+
+ if (tt == "%right") left = false;
+
+ foreach (var ii in rr.Select(x => x.Trim()))
+ {
+ if (string.IsNullOrEmpty(ii)) continue;
+ if (terminals.ContainsKey(ii))
+ items2.Add(terminals[ii]);
+ else if (prec.ContainsKey(ii))
+ items1.AddRange(prec[ii]);
+ else
+ {
+ rtbPGS.Text = $"Conflict rule applying error!\r\n{ii} is neither terminal nor %prec!\r\nDeclare the token-name!";
+ return;
+ }
+ }
+
+ if (items1.Count > 0)
+ gen.PushConflictSolver(left, items1.ToArray());
+ else
+ gen.PushConflictSolver(left, items2.ToArray());
+ }
+
+ rtbPGS.Clear();
+ gen.GlobalPrinter.Clear();
+ gen.PushStarts(non_terminals[rtbPGNT.Text.Split(',')[0].Trim()]);
+ if (rbSLR.Checked == true)
+ {
+ gen.Generate();
+ }
+ else if (rbLALR0.Checked == true)
+ {
+ gen.GenerateLALR2();
+ }
+ else if (rbLALR.Checked == true)
+ {
+ gen.GenerateLALR();
+ }
+ else
+ {
+ gen.GenerateLR1();
+ }
+ gen.PrintStates();
+ gen.PrintTable();
+ rtbPGS.AppendText(gen.GlobalPrinter.ToString());
+ srparser = gen.CreateShiftReduceParserInstance();
+ } catch (Exception ex)
+ {
+ rtbPGS.AppendText(gen.GlobalPrinter.ToString());
+ rtbPGS.AppendText("Generate Error!\r\n" + ex.Message + "\r\n" + ex.StackTrace);
+ }
+ }
+
+ private void bPGT_Click(object sender, EventArgs e)
+ {
+ if (scanner == null)
+ {
+ rtbPGS.AppendText("Create scanner instance before testing!\r\n");
+ return;
+ }
+
+ if (srparser == null)
+ {
+ rtbPGS.AppendText("Create parser instance before testing!\r\n");
+ return;
+ }
+
+ foreach (var line in rtbPGTEST.Lines)
+ {
+ rtbPGS.AppendText(" ------ TEST: " + line + "\r\n");
+
+ srparser.Clear();
+ Action insert = (string x, string y) =>
+ {
+ srparser.Insert(x, y);
+ if (srparser.Error())
+ rtbPGS.AppendText("PARSING ERROR" + "\r\n");
+ while (srparser.Reduce())
+ {
+ rtbPGS.AppendText(srparser.Stack() + "\r\n");
+ var l = srparser.LatestReduce();
+ rtbPGS.AppendText(l.Production.PadLeft(8) + " => ");
+ rtbPGS.AppendText(string.Join(" ", l.Childs.Select(z => z.Production)) + "\r\n");
+ rtbPGS.AppendText(l.Production.PadLeft(8) + " => ");
+ rtbPGS.AppendText(string.Join(" ", l.Childs.Select(z => z.Contents)) + "\r\n");
+ srparser.Insert(x, y);
+ if (srparser.Error())
+ rtbPGS.AppendText("PARSING ERROR" + "\r\n");
+ }
+ rtbPGS.AppendText(srparser.Stack() + "\r\n");
+ };
+
+ scanner.AllocateTarget(line);
+
+ try
+ {
+ while (scanner.Valid())
+ {
+ var ss = scanner.Next();
+ insert(ss.Item1, ss.Item2);
+ }
+ insert("$", "$");
+
+ var x = srparser.Tree;
+ }
+ catch (Exception ex)
+ {
+ rtbPGS.AppendText("Error!\r\nCheck test case!\r\n");
+ }
+
+ rtbPGS.AppendText(" ------ END TEST ------\r\n");
+ }
+ }
+
+ private void rtbPGS_TextChanged(object sender, EventArgs e)
+ {
+ rtbPGS.SelectionStart = rtbPGS.Text.Length;
+ rtbPGS.ScrollToCaret();
+ }
+ }
+}
diff --git a/InhaCC/MainForm.resx b/InhaCC/MainForm.resx
new file mode 100644
index 0000000..29dcb1b
--- /dev/null
+++ b/InhaCC/MainForm.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/InhaCC/Program.cs b/InhaCC/Program.cs
new file mode 100644
index 0000000..fb1fa02
--- /dev/null
+++ b/InhaCC/Program.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace InhaCC
+{
+ static class Program
+ {
+ ///
+ /// 해당 응용 프로그램의 주 진입점입니다.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new MainForm());
+ }
+ }
+}
diff --git a/InhaCC/Properties/AssemblyInfo.cs b/InhaCC/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..baeda1c
--- /dev/null
+++ b/InhaCC/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
+// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
+// 이러한 특성 값을 변경하세요.
+[assembly: AssemblyTitle("InhaCC")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("InhaCC")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
+// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
+// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
+[assembly: ComVisible(false)]
+
+// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
+[assembly: Guid("f608db8c-f9f1-40c1-866f-ba348e566e64")]
+
+// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
+//
+// 주 버전
+// 부 버전
+// 빌드 번호
+// 수정 버전
+//
+// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호가 자동으로
+// 지정되도록 할 수 있습니다.
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/InhaCC/Properties/Resources.Designer.cs b/InhaCC/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..b83d372
--- /dev/null
+++ b/InhaCC/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// 이 코드는 도구를 사용하여 생성되었습니다.
+// 런타임 버전:4.0.30319.42000
+//
+// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
+// 이러한 변경 내용이 손실됩니다.
+//
+//------------------------------------------------------------------------------
+
+namespace InhaCC.Properties {
+ using System;
+
+
+ ///
+ /// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
+ ///
+ // 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
+ // 클래스에서 자동으로 생성되었습니다.
+ // 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여 ResGen을
+ // 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("InhaCC.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대한 현재 스레드의 CurrentUICulture
+ /// 속성을 재정의합니다.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/InhaCC/Properties/Resources.resx b/InhaCC/Properties/Resources.resx
new file mode 100644
index 0000000..ffecec8
--- /dev/null
+++ b/InhaCC/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/InhaCC/Properties/Settings.Designer.cs b/InhaCC/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..fc6e4bb
--- /dev/null
+++ b/InhaCC/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// 이 코드는 도구를 사용하여 생성되었습니다.
+// 런타임 버전:4.0.30319.42000
+//
+// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
+// 이러한 변경 내용이 손실됩니다.
+//
+//------------------------------------------------------------------------------
+
+namespace InhaCC.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/InhaCC/Properties/Settings.settings b/InhaCC/Properties/Settings.settings
new file mode 100644
index 0000000..abf36c5
--- /dev/null
+++ b/InhaCC/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/InhaCC/cc/ParserGenerator.cs b/InhaCC/cc/ParserGenerator.cs
new file mode 100644
index 0000000..b7b4649
--- /dev/null
+++ b/InhaCC/cc/ParserGenerator.cs
@@ -0,0 +1,2827 @@
+/*
+
+ Copyright (C) 2019. rollrat All Rights Reserved.
+
+ Author: Jeong HyunJun
+
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace ParserGenerator
+{
+ #region Parser Production
+
+ public class ParserAction
+ {
+ public Action SemanticAction;
+ public static ParserAction Create(Action action)
+ => new ParserAction { SemanticAction = action };
+ }
+
+ public class ParserProduction
+ {
+ public int index;
+ public string production_name;
+ public bool isterminal;
+ public List contents = new List();
+ public List> sub_productions = new List>();
+ public List temp_actions = new List();
+ public List actions = new List();
+ ParserGenerator parent;
+
+ public ParserProduction(ParserGenerator parent) { this.parent = parent; }
+
+ public static ParserProduction operator +(ParserProduction p1, ParserProduction p2)
+ {
+ p1.contents.Add(p2);
+ return p1;
+ }
+
+ public static ParserProduction operator +(ParserProduction pp, ParserAction ac)
+ {
+ pp.temp_actions.Add(ac);
+ return pp;
+ }
+
+ public static ParserProduction operator +(ParserProduction pp, string name)
+ {
+ pp.contents.Add(pp.parent.TryCreateNewProduction(name));
+ return pp;
+ }
+
+ public static ParserProduction operator +(string name, ParserProduction pp)
+ {
+ var p = pp.parent.TryCreateNewProduction(name);
+ p.contents.Add(pp);
+ return p;
+ }
+
+ public static ParserProduction operator |(ParserProduction p1, ParserProduction p2)
+ {
+ p2.contents.Insert(0, p2);
+ p1.sub_productions.Add(new List(p2.contents));
+ p1.actions.AddRange(p2.temp_actions);
+ p2.temp_actions.Clear();
+ p2.contents.Clear();
+ return p1;
+ }
+
+ public static ParserProduction operator |(ParserProduction p1, string pt2)
+ {
+ var p2 = p1.parent.TryCreateNewProduction(pt2);
+ p2.contents.Insert(0, p2);
+ p1.sub_productions.Add(new List(p2.contents));
+ p1.actions.AddRange(p2.temp_actions);
+ p2.temp_actions.Clear();
+ p2.contents.Clear();
+ return p1;
+ }
+
+#if false
+ public static ParserProduction operator +(ParserProduction p1, string p2)
+ {
+ p1.contents.Add(new ParserProduction { isterminal = true, token_specific = p2 });
+ return p1;
+ }
+
+ public static ParserProduction operator|(ParserProduction p1, string p2)
+ {
+ p1.sub_productions.Add(new List { p1, new ParserProduction { isterminal = true, token_specific = p2 } });
+ return p1;
+ }
+#endif
+ }
+
+ #endregion
+
+ ///
+ /// LR Parser Generator
+ ///
+ public class ParserGenerator
+ {
+ List production_rules;
+ Dictionary production_dict;
+ // (production_index, (priority, is_left_associativity?))
+ Dictionary> shift_reduce_conflict_solve;
+ // (production_index, (sub_production_index, (priority, is_left_associativity?)))
+ Dictionary>> shift_reduce_conflict_solve_with_production_rule;
+
+ public StringBuilder GlobalPrinter = new StringBuilder();
+
+ public readonly static ParserProduction EmptyString = new ParserProduction(null) { index = -2 };
+
+ public ParserGenerator()
+ {
+ production_rules = new List();
+ production_rules.Add(new ParserProduction(this) { index = 0, production_name = "S'" });
+ production_dict = new Dictionary();
+ production_dict.Add("S'", production_rules[0]);
+ shift_reduce_conflict_solve = new Dictionary>();
+ shift_reduce_conflict_solve_with_production_rule = new Dictionary>>();
+ }
+
+ #region Parser Generating Helper
+
+ public ParserProduction CreateNewProduction(string name = "", bool is_terminal = true)
+ {
+ var pp = new ParserProduction(this) { index = production_rules.Count, production_name = name, isterminal = is_terminal };
+ if (production_dict.ContainsKey(name))
+ throw new Exception(name + " is already exsits production!");
+ production_dict.Add(name, pp);
+ production_rules.Add(pp);
+ return pp;
+ }
+
+ public ParserProduction TryCreateNewProduction(string name = "", bool is_terminal = true)
+ {
+ if (production_dict.ContainsKey(name))
+ return production_dict[name];
+ var pp = new ParserProduction(this) { index = production_rules.Count, production_name = name, isterminal = is_terminal };
+ production_dict.Add(name, pp);
+ production_rules.Add(pp);
+ return pp;
+ }
+
+ public void PushStarts(ParserProduction pp)
+ {
+ // Augment stats node
+ production_rules[0].sub_productions.Add(new List { pp });
+ }
+
+ ///
+ /// 터미널들의 Shift-Reduce Conflict solve 정보를 넣습니다.
+ ///
+ ///
+ ///
+ public void PushConflictSolver(bool left, params ParserProduction[] terminals)
+ {
+ var priority = shift_reduce_conflict_solve.Count + shift_reduce_conflict_solve_with_production_rule.Count;
+ foreach (var pp in terminals)
+ shift_reduce_conflict_solve.Add(pp.index, new Tuple(priority, left));
+ }
+
+ ///
+ /// 논터미널들의 Shift-Reduce Conflict solve 정보를 넣습니다.
+ ///
+ ///
+ ///
+ public void PushConflictSolver(bool left, params Tuple[] no)
+ {
+ var priority = shift_reduce_conflict_solve.Count + shift_reduce_conflict_solve_with_production_rule.Count;
+ foreach (var ppi in no)
+ {
+ if (!shift_reduce_conflict_solve_with_production_rule.ContainsKey(ppi.Item1.index))
+ shift_reduce_conflict_solve_with_production_rule.Add(ppi.Item1.index, new Dictionary>());
+ shift_reduce_conflict_solve_with_production_rule[ppi.Item1.index].Add(ppi.Item2, new Tuple(priority, left));
+ }
+ }
+
+ #endregion
+
+ #region Simple ParserDescription Parser
+
+ ///
+ /// 문자열로부터 ParserGenerator를 가져옵니다.
+ ///
+ /// 논터미널 심볼
+ /// 터미널 심볼
+ /// 프로덕션 룰
+ /// Shift Reduce 규칙
+ ///
+ public static ParserGenerator GetGenerator(string[] nt_syms, Tuple[] t_syms, string[] production_rules, string[] sr_rules)
+ {
+ var gen = new ParserGenerator();
+ var non_terminals = new Dictionary();
+ var terminals = new Dictionary();
+
+ terminals.Add("''", EmptyString);
+
+ foreach (var nt in nt_syms)
+ non_terminals.Add(nt.Trim(), gen.CreateNewProduction(nt.Trim(), false));
+
+ foreach (var t in t_syms)
+ {
+ var name = t.Item1;
+ var pp = t.Item2;
+
+ terminals.Add(pp, gen.CreateNewProduction(name.Trim()));
+ }
+
+ var prec = new Dictionary>>();
+ foreach (var pp in production_rules)
+ {
+ if (pp.Trim() == "") continue;
+
+ var split = pp.Split(new[] { "->" }, StringSplitOptions.None);
+ var left = split[0].Trim();
+ var right = split[1].Split(' ');
+
+ var prlist = new List();
+ bool stay_prec = false;
+ foreach (var ntt in right)
+ {
+ if (string.IsNullOrEmpty(ntt)) continue;
+ if (ntt == "%prec") { stay_prec = true; continue; }
+ if (stay_prec)
+ {
+ if (!prec.ContainsKey(ntt))
+ prec.Add(ntt, new List>());
+ prec[ntt].Add(new Tuple(non_terminals[left], non_terminals[left].sub_productions.Count));
+ continue;
+ }
+ if (non_terminals.ContainsKey(ntt))
+ prlist.Add(non_terminals[ntt]);
+ else if (terminals.ContainsKey(ntt))
+ prlist.Add(terminals[ntt]);
+ else
+ throw new Exception($"Production rule build error!\r\n{ntt} is neither non-terminal nor terminal!\r\nDeclare the token-name!");
+ }
+ non_terminals[left].sub_productions.Add(prlist);
+ }
+
+ for (int i = sr_rules.Length - 1; i >= 0; i--)
+ {
+ var line = sr_rules[i].Trim();
+ if (line == "") continue;
+ var tt = line.Split(' ')[0];
+ var rr = line.Substring(tt.Length).Trim().Split(',');
+
+ var left = true;
+ var items1 = new List>();
+ var items2 = new List();
+
+ if (tt == "%right") left = false;
+
+ foreach (var ii in rr.Select(x => x.Trim()))
+ {
+ if (string.IsNullOrEmpty(ii)) continue;
+ if (terminals.ContainsKey(ii))
+ items2.Add(terminals[ii]);
+ else if (prec.ContainsKey(ii))
+ items1.AddRange(prec[ii]);
+ else
+ throw new Exception($"Production rule build error!\r\n{ii} is neither non-terminal nor terminal!\r\nDeclare the token-name!");
+ }
+
+ if (items1.Count > 0)
+ gen.PushConflictSolver(left, items1.ToArray());
+ else
+ gen.PushConflictSolver(left, items2.ToArray());
+ }
+
+ gen.PushStarts(non_terminals[nt_syms[0]]);
+
+ return gen;
+ }
+
+ #endregion
+
+ #region String Hash Function
+ // 원래 해시가 아니라 set로 구현해야하는게 일반적임
+ // 집합끼리의 비교연산, 일치여부 교집합을 구해 좀 더 최적화가능하지만 귀찮으니 string-hash를 쓰도록한다.
+ //
+ // # 2019-07-15
+ // 확인결과 별도의 클래스를 만들어 set를 관리하는 것보다 string-hash가 더 빠르다
+ // JSParserGenetor의 경우 set의 경우 13초, string-hash의 경우 11초로 string-hash가 더 빠른 속도를 내었다.
+ // set은 dictionary에서사용하는 GetHashCode 및 Equals 함수와, state의 kernel을 고려하여 만든 클래스였다.
+
+ private string t2s(Tuple t)
+ {
+ return $"{t.Item1},{t.Item2},{t.Item3}";
+ }
+
+ private string t2s(Tuple> t)
+ {
+ var list = t.Item4.ToList();
+ list.Sort();
+ return $"{t.Item1},{t.Item2},{t.Item3},({string.Join(",", list)})";
+ }
+
+ private string l2s(List> h)
+ {
+ var list = h.ToList();
+ list.Sort();
+ return string.Join(",", list.Select(x => $"({x.Item1},{x.Item2},{x.Item3})"));
+ }
+
+ private string l2s(List>> h)
+ {
+ var list = new List>>();
+ foreach (var tt in h)
+ {
+ var ll = tt.Item4.ToList();
+ ll.Sort();
+ list.Add(new Tuple>(tt.Item1, tt.Item2, tt.Item3, ll));
+ }
+ list.Sort();
+ return string.Join(",", list.Select(x => $"({x.Item1},{x.Item2},{x.Item3},({(string.Join("/", x.Item4))}))"));
+ }
+
+ private static string l2sl(List>> h, int kernel_cnt)
+ {
+ var list = new List>();
+ var builder = new StringBuilder();
+ for (int i = 0; i < kernel_cnt; i++)
+ list.Add(new Tuple(h[i].Item1, h[i].Item2, h[i].Item3));
+ list.Sort();
+ return string.Join(",", list.Select(x => $"({x.Item1},{x.Item2},{x.Item3})"));
+ }
+
+ private string i2s(int a, int b, int c)
+ {
+ return $"{a},{b},{c}";
+ }
+ #endregion
+
+ #region Debug Printer
+
+ private void print_hs(List> lhs, string prefix)
+ {
+ for (int i = 0; i < lhs.Count; i++)
+ if (lhs[i].Count > 0)
+ GlobalPrinter.Append(
+ $"{prefix}({production_rules[i].production_name})={{{string.Join(",", lhs[i].ToList().Select(x => x == -1 ? "$" : production_rules[x].production_name))}}}\r\n");
+ }
+
+ private void print_header(string head_text)
+ {
+ GlobalPrinter.Append("\r\n" + new string('=', 50) + "\r\n\r\n");
+ int spaces = 50 - head_text.Length;
+ int padLeft = spaces / 2 + head_text.Length;
+ GlobalPrinter.Append(head_text.PadLeft(padLeft).PadRight(50));
+ GlobalPrinter.Append("\r\n\r\n" + new string('=', 50) + "\r\n");
+ }
+
+ private void print_states(int state, List>> items)
+ {
+ var builder = new StringBuilder();
+ builder.Append("-----" + "I" + state + "-----\r\n");
+
+ foreach (var item in items)
+ {
+ builder.Append($"{production_rules[item.Item1].production_name.ToString().PadLeft(10)} -> ");
+
+ var builder2 = new StringBuilder();
+ for (int i = 0; i < production_rules[item.Item1].sub_productions[item.Item2].Count; i++)
+ {
+ if (i == item.Item3)
+ builder2.Append("·");
+ builder2.Append(production_rules[item.Item1].sub_productions[item.Item2][i].production_name + " ");
+ if (item.Item3 == production_rules[item.Item1].sub_productions[item.Item2].Count && i == item.Item3 - 1)
+ builder2.Append("·");
+ }
+ builder.Append(builder2.ToString().PadRight(30));
+
+ builder.Append($"{string.Join("/", item.Item4.ToList().Select(x => x == -1 ? "$" : production_rules[x].production_name))}\r\n");
+ }
+
+ GlobalPrinter.Append(builder.ToString());
+ }
+
+ private void print_merged_states(int state, List>> items, List>> external_gotos)
+ {
+ var builder = new StringBuilder();
+ builder.Append("-----" + "I" + state + "-----\r\n");
+
+ for (int j = 0; j < items.Count; j++)
+ {
+ var item = items[j];
+
+ builder.Append($"{production_rules[item.Item1].production_name.ToString().PadLeft(10)} -> ");
+
+ var builder2 = new StringBuilder();
+ for (int i = 0; i < production_rules[item.Item1].sub_productions[item.Item2].Count; i++)
+ {
+ if (i == item.Item3)
+ builder2.Append("·");
+ builder2.Append(production_rules[item.Item1].sub_productions[item.Item2][i].production_name + " ");
+ if (item.Item3 == production_rules[item.Item1].sub_productions[item.Item2].Count && i == item.Item3 - 1)
+ builder2.Append("·");
+ }
+ builder.Append(builder2.ToString().PadRight(30));
+
+ builder.Append($"[{string.Join("/", item.Item4.ToList().Select(x => x == -1 ? "$" : production_rules[x].production_name))}] ");
+ for (int i = 0; i < external_gotos.Count; i++)
+ builder.Append($"[{string.Join("/", external_gotos[i][j].ToList().Select(x => x == -1 ? "$" : production_rules[x].production_name))}] ");
+ builder.Append("\r\n");
+ }
+
+ GlobalPrinter.Append(builder.ToString());
+ }
+
+ #endregion
+
+ int number_of_states = -1;
+ Dictionary>> shift_info;
+ Dictionary>> reduce_info;
+
+ #region SLR Generator
+ ///
+ /// Generate SimpleLR Table
+ ///
+ public void Generate()
+ {
+ // --------------- Expand EmptyString ---------------
+ for (int i = 0; i < production_rules.Count; i++)
+ if (!production_rules[i].isterminal)
+ for (int j = 0; j < production_rules[i].sub_productions.Count; j++)
+ if (production_rules[i].sub_productions[j][0].index == EmptyString.index)
+ {
+ production_rules[i].sub_productions.RemoveAt(j--);
+ for (int ii = 0; ii < production_rules.Count; ii++)
+ if (!production_rules[ii].isterminal)
+ for (int jj = 0; jj < production_rules[ii].sub_productions.Count; jj++)
+ for (int kk = 0; kk < production_rules[ii].sub_productions[jj].Count; kk++)
+ if (production_rules[ii].sub_productions[jj][kk].index == production_rules[i].index)
+ {
+ var ll = new List(production_rules[ii].sub_productions[jj]);
+ ll.RemoveAt(kk);
+ production_rules[ii].sub_productions.Add(ll);
+ }
+ }
+ // --------------------------------------------------
+
+ // --------------- Collect FIRST,FOLLOW Set ---------------
+ var FIRST = new List>();
+ foreach (var rule in production_rules)
+ FIRST.Add(first_terminals(rule.index));
+
+ var FOLLOW = follow_terminals(FIRST);
+
+#if true
+ print_header("FISRT, FOLLOW SETS");
+ print_hs(FIRST, "FIRST");
+ print_hs(FOLLOW, "FOLLOW");
+#endif
+ // --------------------------------------------------------
+
+ // (state_index, (production_rule_index, sub_productions_pos, dot_position)
+ var states = new Dictionary>>();
+ // (state_specify, state_index)
+ var state_index = new Dictionary();
+ // (state_index, (reduce_what, state_index))
+ shift_info = new Dictionary>>();
+ // (state_index, (shift_what, production_rule_index, sub_productions_pos))
+ reduce_info = new Dictionary>>();
+ var index_count = 0;
+
+ // -------------------- Put first eater -------------------
+ var first_l = first_nonterminals(0);
+ state_index.Add(l2s(first_l), 0);
+ states.Add(0, first_l);
+ // --------------------------------------------------------
+
+ // Create all LR states
+ // (states)
+ var q = new Queue();
+ q.Enqueue(index_count++);
+ while (q.Count != 0)
+ {
+ var p = q.Dequeue();
+
+ // Collect goto
+ // (state_index, (production_rule_index, sub_productions_pos, dot_position))
+ var gotos = new Dictionary>>();
+ foreach (var transition in states[p])
+ if (production_rules[transition.Item1].sub_productions[transition.Item2].Count > transition.Item3)
+ {
+ var pi = production_rules[transition.Item1].sub_productions[transition.Item2][transition.Item3].index;
+ if (!gotos.ContainsKey(pi))
+ gotos.Add(pi, new List>());
+ gotos[pi].Add(new Tuple(transition.Item1, transition.Item2, transition.Item3 + 1));
+ }
+
+ // Populate empty-string closure
+ foreach (var goto_unit in gotos)
+ {
+ var set = new HashSet();
+ // Push exists transitions
+ foreach (var psd in goto_unit.Value)
+ set.Add(t2s(psd));
+ // Find all transitions
+ var new_trans = new List>();
+ foreach (var psd in goto_unit.Value)
+ {
+ if (production_rules[psd.Item1].sub_productions[psd.Item2].Count == psd.Item3) continue;
+ if (production_rules[psd.Item1].sub_productions[psd.Item2][psd.Item3].isterminal) continue;
+ var first_nt = first_nonterminals(production_rules[psd.Item1].sub_productions[psd.Item2][psd.Item3].index);
+ foreach (var nts in first_nt)
+ if (!set.Contains(t2s(nts)))
+ {
+ new_trans.Add(nts);
+ set.Add(t2s(nts));
+ }
+ }
+ goto_unit.Value.AddRange(new_trans);
+ }
+
+ // Build shift transitions ignore terminal, non-terminal
+ foreach (var pp in gotos)
+ {
+ var hash = l2s(pp.Value);
+ if (!state_index.ContainsKey(hash))
+ {
+ states.Add(index_count, pp.Value);
+ state_index.Add(hash, index_count);
+ q.Enqueue(index_count++);
+ }
+ var index = state_index[hash];
+
+ if (!shift_info.ContainsKey(p))
+ shift_info.Add(p, new List>());
+ shift_info[p].Add(new Tuple(pp.Key, index));
+ }
+
+ // Check require reduce and build reduce transitions
+ foreach (var transition in states[p])
+ if (production_rules[transition.Item1].sub_productions[transition.Item2].Count == transition.Item3)
+ {
+ if (!reduce_info.ContainsKey(p))
+ reduce_info.Add(p, new List>());
+ foreach (var term in FOLLOW[transition.Item1])
+ reduce_info[p].Add(new Tuple(term, transition.Item1, transition.Item2));
+ }
+ }
+
+ number_of_states = states.Count;
+ }
+ #endregion
+
+ #region LR(1) Generator
+ ///
+ /// Generate LR(1) Table
+ ///
+ /// There is a lookahead propagation error while trying to get the LR(1) item, and it is under review.
+ /// Don't use this function
+ ///
+ public void GenerateLR1()
+ {
+ // --------------- Delete EmptyString ---------------
+ for (int i = 0; i < production_rules.Count; i++)
+ if (!production_rules[i].isterminal)
+ for (int j = 0; j < production_rules[i].sub_productions.Count; j++)
+ if (production_rules[i].sub_productions[j][0].index == EmptyString.index)
+ production_rules[i].sub_productions[j].Clear();
+ // --------------------------------------------------
+
+ // --------------- Collect FIRST,FOLLOW Set ---------------
+ var FIRST = new List>();
+ foreach (var rule in production_rules)
+ FIRST.Add(first_terminals(rule.index));
+
+ var FOLLOW = follow_terminals(FIRST);
+
+#if true
+ print_header("FISRT, FOLLOW SETS");
+ print_hs(FIRST, "FIRST");
+ print_hs(FOLLOW, "FOLLOW");
+#endif
+ // --------------------------------------------------------
+
+ // (state_index, (production_rule_index, sub_productions_pos, dot_position, (lookahead))
+ var states = new Dictionary>>>();
+ // (state_specify, state_index)
+ var state_index = new Dictionary();
+ var goto_table = new List>>>();
+ // (state_index, (reduce_what, state_index))
+ shift_info = new Dictionary>>();
+ // (state_index, (shift_what, production_rule_index, sub_productions_pos))
+ reduce_info = new Dictionary>>();
+ var index_count = 0;
+
+ // -------------------- Put first eater -------------------
+ var first_l = first_with_lookahead(0, 0, 0, new HashSet());
+ state_index.Add(l2s(first_l), 0);
+ states.Add(0, first_l);
+ // --------------------------------------------------------
+
+ // Create all LR states
+ // (states)
+ var q = new Queue();
+ q.Enqueue(index_count++);
+ while (q.Count != 0)
+ {
+ var p = q.Dequeue();
+
+ // Collect goto
+ // (state_index, (production_rule_index, sub_productions_pos, dot_position, lookahead))
+ var gotos = new Dictionary>>>();
+ foreach (var transition in states[p])
+ if (production_rules[transition.Item1].sub_productions[transition.Item2].Count > transition.Item3)
+ {
+ var pi = production_rules[transition.Item1].sub_productions[transition.Item2][transition.Item3].index;
+ if (!gotos.ContainsKey(pi))
+ gotos.Add(pi, new List>>());
+ gotos[pi].Add(new Tuple>(transition.Item1, transition.Item2, transition.Item3 + 1, transition.Item4));
+ }
+
+ // Populate empty-string closure
+ foreach (var goto_unit in gotos)
+ {
+ var set = new HashSet();
+ // Push exists transitions
+ foreach (var psd in goto_unit.Value)
+ set.Add(t2s(psd));
+ // Find all transitions
+ var new_trans = new List>>();
+ var trans_dic = new Dictionary();
+ foreach (var psd in goto_unit.Value)
+ {
+ if (production_rules[psd.Item1].sub_productions[psd.Item2].Count == psd.Item3) continue;
+ if (production_rules[psd.Item1].sub_productions[psd.Item2][psd.Item3].isterminal) continue;
+ var first_nt = first_with_lookahead(psd.Item1, psd.Item2, psd.Item3, psd.Item4);
+ foreach (var nts in first_nt)
+ if (!set.Contains(t2s(nts)))
+ {
+ var ts = t2s(new Tuple(nts.Item1, nts.Item2, nts.Item3));
+ if (trans_dic.ContainsKey(ts))
+ {
+ nts.Item4.ToList().ForEach(x => new_trans[trans_dic[ts]].Item4.Add(x));
+ }
+ else
+ {
+ trans_dic.Add(ts, new_trans.Count);
+ new_trans.Add(nts);
+ set.Add(t2s(nts));
+ }
+ }
+ }
+ goto_unit.Value.AddRange(new_trans);
+ }
+
+ //// Build shift transitions ignore terminal, non-terminal
+ //foreach (var pp in gotos)
+ //{
+ // var hash = l2s(pp.Value);
+ // if (!state_index.ContainsKey(hash))
+ // {
+ // states.Add(index_count, pp.Value);
+ // state_index.Add(hash, index_count);
+ // q.Enqueue(index_count++);
+ // }
+ // var index = state_index[hash];
+ //
+ // if (!shift_info.ContainsKey(p))
+ // shift_info.Add(p, new List>());
+ // shift_info[p].Add(new Tuple(pp.Key, index));
+ //}
+ //
+ //// Check require reduce and build reduce transitions
+ //foreach (var transition in states[p])
+ // if (production_rules[transition.Item1].sub_productions[transition.Item2].Count == transition.Item3)
+ // {
+ // if (!reduce_info.ContainsKey(p))
+ // reduce_info.Add(p, new List>());
+ // foreach (var term in transition.Item4)
+ // reduce_info[p].Add(new Tuple(term, transition.Item1, transition.Item2));
+ // }
+
+ // Build goto transitions ignore terminal, non-terminal anywhere
+ var index_list = new List>();
+ foreach (var pp in gotos)
+ {
+ var hash = l2s(pp.Value);
+ if (!state_index.ContainsKey(hash))
+ {
+ states.Add(index_count, pp.Value);
+ state_index.Add(hash, index_count);
+ q.Enqueue(index_count++);
+ }
+ index_list.Add(new Tuple(pp.Key, state_index[hash]));
+ }
+
+ goto_table.Add(new Tuple>>(p, index_list));
+ }
+
+ var occurred_conflict = false;
+
+ // ------------- Find Shift-Reduce Conflict ------------
+ foreach (var ms in states)
+ {
+ // (shift_what, state_index)
+ var small_shift_info = new List>();
+ // (reduce_what, production_rule_index, sub_productions_pos)
+ var small_reduce_info = new List>();
+
+ // Fill Shift Info
+ foreach (var pp in goto_table[ms.Key].Item2)
+ small_shift_info.Add(new Tuple(pp.Item1, pp.Item2));
+
+ // Fill Reduce Info
+ foreach (var transition in ms.Value)
+ if (production_rules[transition.Item1].sub_productions[transition.Item2].Count == transition.Item3)
+ {
+ foreach (var term in transition.Item4)
+ small_reduce_info.Add(new Tuple(term, transition.Item1, transition.Item2));
+ }
+
+ // Conflict Check
+ // (shift_what, small_shift_info_index)
+ var shift_tokens = new Dictionary();
+ for (int i = 0; i < small_shift_info.Count; i++)
+ shift_tokens.Add(small_shift_info[i].Item1, i);
+ var completes = new HashSet();
+
+ foreach (var tuple in small_reduce_info)
+ {
+ if (completes.Contains(tuple.Item1))
+ {
+ // It's already added so do not have to work anymore.
+ continue;
+ }
+
+ if (shift_tokens.ContainsKey(tuple.Item1))
+ {
+#if true
+ print_header("SHIFT-REDUCE CONFLICTS");
+ GlobalPrinter.Append($"Shift-Reduce Conflict! {(tuple.Item1 == -1 ? "$" : production_rules[tuple.Item1].production_name)}\r\n");
+ GlobalPrinter.Append($"States: {ms.Key} {small_shift_info[shift_tokens[tuple.Item1]].Item2}\r\n");
+ print_states(ms.Key, states[ms.Key]);
+ print_states(small_shift_info[shift_tokens[tuple.Item1]].Item2, states[small_shift_info[shift_tokens[tuple.Item1]].Item2]);
+#endif
+ Tuple p1 = null, p2 = null;
+
+ try
+ {
+ var pp = get_first_on_right_terminal(production_rules[tuple.Item2], tuple.Item3);
+ if (shift_reduce_conflict_solve.ContainsKey(pp.index))
+ p1 = shift_reduce_conflict_solve[pp.index];
+ }
+ catch (Exception e)
+ {
+ GlobalPrinter.Append(e.Message + "\r\n");
+ }
+
+ if (shift_reduce_conflict_solve.ContainsKey(tuple.Item1))
+ p2 = shift_reduce_conflict_solve[tuple.Item1];
+
+ if (shift_reduce_conflict_solve_with_production_rule.ContainsKey(tuple.Item2))
+ if (shift_reduce_conflict_solve_with_production_rule[tuple.Item2].ContainsKey(tuple.Item3))
+ p1 = shift_reduce_conflict_solve_with_production_rule[tuple.Item2][tuple.Item3];
+
+ //if (shift_reduce_conflict_solve_with_production_rule.ContainsKey(states[tuple.Item1][0].Item1))
+ // if (shift_reduce_conflict_solve_with_production_rule[states[tuple.Item1][0].Item1].ContainsKey(states[tuple.Item1][0].Item2))
+ // p2 = shift_reduce_conflict_solve_with_production_rule[states[tuple.Item1][0].Item1][states[tuple.Item1][0].Item2];
+
+ if (p1 == null || p2 == null)
+ {
+ occurred_conflict = true;
+ continue;
+ }
+
+ if (p1.Item1 < p2.Item1 || (p1.Item1 == p2.Item1 && p1.Item2))
+ {
+ // Reduce
+ if (!reduce_info.ContainsKey(ms.Key))
+ reduce_info.Add(ms.Key, new List>());
+ reduce_info[ms.Key].Add(new Tuple(tuple.Item1, tuple.Item2, tuple.Item3));
+ }
+ else
+ {
+ // Shift
+ if (!shift_info.ContainsKey(ms.Key))
+ shift_info.Add(ms.Key, new List>());
+ shift_info[ms.Key].Add(new Tuple(tuple.Item1, small_shift_info[shift_tokens[tuple.Item1]].Item2));
+ }
+
+ completes.Add(tuple.Item1);
+ }
+ else
+ {
+ // Just add reduce item
+ if (!reduce_info.ContainsKey(ms.Key))
+ reduce_info.Add(ms.Key, new List>());
+ reduce_info[ms.Key].Add(new Tuple(tuple.Item1, tuple.Item2, tuple.Item3));
+
+ completes.Add(tuple.Item1);
+ }
+ }
+
+ foreach (var pair in shift_tokens)
+ {
+ if (completes.Contains(pair.Key)) continue;
+ var shift = small_shift_info[pair.Value];
+ if (!shift_info.ContainsKey(ms.Key))
+ shift_info.Add(ms.Key, new List>());
+ shift_info[ms.Key].Add(new Tuple(shift.Item1, shift.Item2));
+ }
+ }
+ // -----------------------------------------------------
+
+ if (occurred_conflict)
+ throw new Exception("Specify the rules to resolve Shift-Reduce Conflict!");
+
+ number_of_states = states.Count;
+#if true
+ print_header("STATES INFO");
+ foreach (var s in states)
+ print_states(s.Key, s.Value);
+#endif
+ }
+ #endregion
+
+ #region LALR Generator
+ ///
+ /// Generate LALR Table
+ ///
+ public void GenerateLALR()
+ {
+ // --------------- Delete EmptyString ---------------
+ for (int i = 0; i < production_rules.Count; i++)
+ if (!production_rules[i].isterminal)
+ for (int j = 0; j < production_rules[i].sub_productions.Count; j++)
+ if (production_rules[i].sub_productions[j][0].index == EmptyString.index)
+ production_rules[i].sub_productions[j].Clear();
+ // --------------------------------------------------
+
+ // --------------- Collect FIRST,FOLLOW Set ---------------
+ var FIRST = new List>();
+ foreach (var rule in production_rules)
+ FIRST.Add(first_terminals(rule.index));
+
+ var FOLLOW = follow_terminals(FIRST);
+
+#if true
+ print_header("FISRT, FOLLOW SETS");
+ print_hs(FIRST, "FIRST");
+ print_hs(FOLLOW, "FOLLOW");
+#endif
+ // --------------------------------------------------------
+
+ // (state_index, (production_rule_index, sub_productions_pos, dot_position, (lookahead))
+ var states = new Dictionary>>>();
+ // (state_specify, state_index)
+ var state_index = new Dictionary();
+ var goto_table = new List>>>();
+ // (state_index, (shift_what, state_index))
+ shift_info = new Dictionary>>();
+ // (state_index, (reduce_what, production_rule_index, sub_productions_pos))
+ reduce_info = new Dictionary>>();
+ var index_count = 0;
+
+ // -------------------- Put first eater -------------------
+ var first_l = first_with_lookahead(0, 0, 0, new HashSet());
+ state_index.Add(l2s(first_l), 0);
+ states.Add(0, first_l);
+ // --------------------------------------------------------
+
+ // Create all LR states
+ // (states)
+ var q = new Queue();
+ q.Enqueue(index_count++);
+ while (q.Count != 0)
+ {
+ var p = q.Dequeue();
+
+ // Collect goto
+ // (state_index, (production_rule_index, sub_productions_pos, dot_position, lookahead))
+ var gotos = new Dictionary>>>();
+ foreach (var transition in states[p])
+ if (production_rules[transition.Item1].sub_productions[transition.Item2].Count > transition.Item3)
+ {
+ var pi = production_rules[transition.Item1].sub_productions[transition.Item2][transition.Item3].index;
+ if (!gotos.ContainsKey(pi))
+ gotos.Add(pi, new List>>());
+ gotos[pi].Add(new Tuple>(transition.Item1, transition.Item2, transition.Item3 + 1, transition.Item4));
+ }
+
+ // Populate empty-string closure
+ foreach (var goto_unit in gotos)
+ {
+ var set = new HashSet();
+ // Push exists transitions
+ foreach (var psd in goto_unit.Value)
+ set.Add(t2s(psd));
+ // Find all transitions
+ var new_trans = new List>>();
+ var trans_dic = new Dictionary();
+ foreach (var psd in goto_unit.Value)
+ {
+ if (production_rules[psd.Item1].sub_productions[psd.Item2].Count == psd.Item3) continue;
+ if (production_rules[psd.Item1].sub_productions[psd.Item2][psd.Item3].isterminal) continue;
+ var first_nt = first_with_lookahead(psd.Item1, psd.Item2, psd.Item3, psd.Item4);
+ foreach (var nts in first_nt)
+ if (!set.Contains(t2s(nts)))
+ {
+ var ts = t2s(new Tuple(nts.Item1, nts.Item2, nts.Item3));
+ if (trans_dic.ContainsKey(ts))
+ {
+ nts.Item4.ToList().ForEach(x => new_trans[trans_dic[ts]].Item4.Add(x));
+ }
+ else
+ {
+ trans_dic.Add(ts, new_trans.Count);
+ new_trans.Add(nts);
+ set.Add(t2s(nts));
+ }
+ }
+ }
+ goto_unit.Value.AddRange(new_trans);
+ }
+
+ // Build goto transitions ignore terminal, non-terminal anywhere
+ var index_list = new List>();
+ foreach (var pp in gotos)
+ {
+ try
+ {
+ var hash = l2s(pp.Value);
+ if (!state_index.ContainsKey(hash))
+ {
+ states.Add(index_count, pp.Value);
+ state_index.Add(hash, index_count);
+ q.Enqueue(index_count++);
+ }
+ index_list.Add(new Tuple(pp.Key, state_index[hash]));
+ }
+ catch
+ {
+ // Now this error is not hit
+ // For debugging
+ print_header("GOTO CONFLICT!!");
+ GlobalPrinter.Append($"Cannot solve lookahead overlapping!\r\n");
+ GlobalPrinter.Append($"Please uses non-associative option or adds extra token to handle with shift-reduce conflict!\r\n");
+ print_states(p, states[p]);
+ print_header("INCOMPLETE STATES");
+ foreach (var s in states)
+ print_states(s.Key, s.Value);
+ return;
+ }
+ }
+
+ goto_table.Add(new Tuple>>(p, index_list));
+ }
+
+#if true
+ print_header("UNMERGED STATES");
+ foreach (var s in states)
+ print_states(s.Key, s.Value);
+#endif
+
+ // -------------------- Merge States -------------------
+ var merged_states = new Dictionary>();
+ var merged_states_index = new Dictionary();
+ var merged_index = new Dictionary();
+ var merged_merged_index = new Dictionary();
+ var merged_merged_inverse_index = new Dictionary();
+ var count_of_completes_states = 0;
+
+ for (int i = 0; i < states.Count; i++)
+ {
+ var str = l2s(states[i].Select(x => new Tuple(x.Item1, x.Item2, x.Item3)).ToList());
+
+ if (!merged_states_index.ContainsKey(str))
+ {
+ merged_states_index.Add(str, i);
+ merged_states.Add(i, new List());
+ merged_index.Add(i, i);
+ merged_merged_inverse_index.Add(str, count_of_completes_states);
+ merged_merged_index.Add(i, count_of_completes_states++);
+ }
+ else
+ {
+ merged_states[merged_states_index[str]].Add(i);
+ merged_index.Add(i, merged_states_index[str]);
+ merged_merged_index.Add(i, merged_merged_inverse_index[str]);
+ }
+ }
+
+#if true
+ print_header("MERGED STATES WITH SOME SETS");
+ foreach (var s in merged_states)
+ print_merged_states(s.Key, states[s.Key], s.Value.Select(x => states[x].Select(y => y.Item4.ToList()).ToList()).ToList());
+#endif
+
+ foreach (var pair in merged_states)
+ {
+ for (int i = 0; i < states[pair.Key].Count; i++)
+ {
+ foreach (var ii in pair.Value)
+ foreach (var lookahead in states[ii][i].Item4)
+ states[pair.Key][i].Item4.Add(lookahead);
+ }
+ }
+
+#if true
+ print_header("MERGED STATES");
+ foreach (var s in merged_states)
+ print_states(s.Key, states[s.Key]);
+#endif
+ // -----------------------------------------------------
+
+ var occurred_conflict = false;
+
+ // ------------- Find Shift-Reduce Conflict ------------
+ foreach (var ms in merged_states)
+ {
+ // (shift_what, state_index)
+ var small_shift_info = new List>();
+ // (reduce_what, production_rule_index, sub_productions_pos)
+ var small_reduce_info = new List>();
+
+ // Fill Shift Info
+ foreach (var pp in goto_table[ms.Key].Item2)
+ small_shift_info.Add(new Tuple(pp.Item1, merged_index[pp.Item2]));
+
+ // Fill Reduce Info
+ ms.Value.Add(ms.Key);
+ foreach (var index in ms.Value)
+ foreach (var transition in states[index])
+ if (production_rules[transition.Item1].sub_productions[transition.Item2].Count == transition.Item3)
+ {
+ foreach (var term in transition.Item4)
+ small_reduce_info.Add(new Tuple(term, transition.Item1, transition.Item2));
+ }
+
+ // Conflict Check
+ // (shift_what, small_shift_info_index)
+ var shift_tokens = new Dictionary();
+ for (int i = 0; i < small_shift_info.Count; i++)
+ shift_tokens.Add(small_shift_info[i].Item1, i);
+ var completes = new HashSet();
+
+ foreach (var tuple in small_reduce_info)
+ {
+ if (completes.Contains(tuple.Item1))
+ {
+ // It's already added so do not have to work anymore.
+ continue;
+ }
+
+ if (shift_tokens.ContainsKey(tuple.Item1))
+ {
+#if !DEBUG
+ print_header("SHIFT-REDUCE CONFLICTS");
+ GlobalPrinter.Append($"Shift-Reduce Conflict! {(tuple.Item1 == -1 ? "$" : production_rules[tuple.Item1].production_name)}\r\n");
+ GlobalPrinter.Append($"States: {ms.Key} {small_shift_info[shift_tokens[tuple.Item1]].Item2}\r\n");
+ print_states(ms.Key, states[ms.Key]);
+ print_states(small_shift_info[shift_tokens[tuple.Item1]].Item2, states[small_shift_info[shift_tokens[tuple.Item1]].Item2]);
+#endif
+ Tuple p1 = null, p2 = null;
+
+#if DEBUG
+ string mm = "";
+#endif
+ try
+ {
+ var pp = get_first_on_right_terminal(production_rules[tuple.Item2], tuple.Item3);
+ if (shift_reduce_conflict_solve.ContainsKey(pp.index))
+ p1 = shift_reduce_conflict_solve[pp.index];
+ }
+ catch (Exception e)
+ {
+#if !DEBUG
+ GlobalPrinter.Append(e.Message + "\r\n");
+#else
+ mm = e.Message + "\r\n";
+#endif
+ }
+
+ if (shift_reduce_conflict_solve.ContainsKey(tuple.Item1))
+ p2 = shift_reduce_conflict_solve[tuple.Item1];
+
+ if (shift_reduce_conflict_solve_with_production_rule.ContainsKey(tuple.Item2))
+ if (shift_reduce_conflict_solve_with_production_rule[tuple.Item2].ContainsKey(tuple.Item3))
+ p1 = shift_reduce_conflict_solve_with_production_rule[tuple.Item2][tuple.Item3];
+
+ //if (shift_reduce_conflict_solve_with_production_rule.ContainsKey(states[tuple.Item1][0].Item1))
+ // if (shift_reduce_conflict_solve_with_production_rule[states[tuple.Item1][0].Item1].ContainsKey(states[tuple.Item1][0].Item2))
+ // p2 = shift_reduce_conflict_solve_with_production_rule[states[tuple.Item1][0].Item1][states[tuple.Item1][0].Item2];
+
+ if (p1 == null || p2 == null)
+ {
+#if DEBUG
+ print_header("SHIFT-REDUCE CONFLICTS");
+ GlobalPrinter.Append($"Shift-Reduce Conflict! {(tuple.Item1 == -1 ? "$" : production_rules[tuple.Item1].production_name)}\r\n");
+ GlobalPrinter.Append($"States: {ms.Key} {small_shift_info[shift_tokens[tuple.Item1]].Item2}\r\n");
+ print_states(ms.Key, states[ms.Key]);
+ print_states(small_shift_info[shift_tokens[tuple.Item1]].Item2, states[small_shift_info[shift_tokens[tuple.Item1]].Item2]);
+ if (mm != "")
+ GlobalPrinter.Append(mm);
+#endif
+ occurred_conflict = true;
+ continue;
+ }
+
+ if (p1.Item1 < p2.Item1 || (p1.Item1 == p2.Item1 && p1.Item2))
+ {
+ // Reduce
+ if (!reduce_info.ContainsKey(merged_merged_index[ms.Key]))
+ reduce_info.Add(merged_merged_index[ms.Key], new List>());
+ reduce_info[merged_merged_index[ms.Key]].Add(new Tuple(tuple.Item1, tuple.Item2, tuple.Item3));
+ }
+ else
+ {
+ // Shift
+ if (!shift_info.ContainsKey(merged_merged_index[ms.Key]))
+ shift_info.Add(merged_merged_index[ms.Key], new List>());
+ shift_info[merged_merged_index[ms.Key]].Add(new Tuple(tuple.Item1, merged_merged_index[small_shift_info[shift_tokens[tuple.Item1]].Item2]));
+ }
+
+ completes.Add(tuple.Item1);
+ }
+ else
+ {
+ // Just add reduce item
+ if (!reduce_info.ContainsKey(merged_merged_index[ms.Key]))
+ reduce_info.Add(merged_merged_index[ms.Key], new List>());
+ reduce_info[merged_merged_index[ms.Key]].Add(new Tuple(tuple.Item1, tuple.Item2, tuple.Item3));
+
+ completes.Add(tuple.Item1);
+ }
+ }
+
+ foreach (var pair in shift_tokens)
+ {
+ if (completes.Contains(pair.Key)) continue;
+ var shift = small_shift_info[pair.Value];
+ if (!shift_info.ContainsKey(merged_merged_index[ms.Key]))
+ shift_info.Add(merged_merged_index[ms.Key], new List>());
+ shift_info[merged_merged_index[ms.Key]].Add(new Tuple(shift.Item1, merged_merged_index[shift.Item2]));
+ }
+ }
+ // -----------------------------------------------------
+
+ if (occurred_conflict)
+ throw new Exception("Specify the rules to resolve Shift-Reduce Conflict!");
+
+ number_of_states = merged_states.Count;
+ }
+ #endregion
+
+ #region LALR Generator From LR(0) Items
+
+ ///
+ /// http://3e8.org/pub/scheme/doc/parsing/Efficient%20Computation%20of%20LALR(1)%20Look-Ahead%20Sets.pdf
+ ///
+ /// DEREMER, Frank; PENNELLO, Thomas. Efficient computation of LALR (1) look-ahead sets.
+ /// ACM Transactions on Programming Languages and Systems (TOPLAS), 1982, 4.4: 615-649.
+ ///
+ /// Dragon Book 4.7.5 - Efficient Construction of LALR Parsing Table
+ ///
+ public void GenerateLALR2()
+ {
+ // --------------- Delete EmptyString ---------------
+ for (int i = 0; i < production_rules.Count; i++)
+ if (!production_rules[i].isterminal)
+ for (int j = 0; j < production_rules[i].sub_productions.Count; j++)
+ if (production_rules[i].sub_productions[j][0].index == EmptyString.index)
+ production_rules[i].sub_productions[j].Clear();
+ // --------------------------------------------------
+
+ // --------------- Collect FIRST,FOLLOW Set ---------------
+ var FIRST = new List>();
+ foreach (var rule in production_rules)
+ FIRST.Add(first_terminals(rule.index));
+
+ var FOLLOW = follow_terminals(FIRST);
+
+#if true
+ print_header("FISRT, FOLLOW SETS");
+ print_hs(FIRST, "FIRST");
+ print_hs(FOLLOW, "FOLLOW");
+#endif
+ // --------------------------------------------------------
+
+ // --------------- Determine exists epsillon ---------------
+ var include_epsillon = Enumerable.Repeat(false, production_rules.Count).ToList();
+
+ for (int i = 0; i < production_rules.Count; i++)
+ if (!production_rules[i].isterminal)
+ if (production_rules[i].sub_productions.Any(x => x.Count == 0))
+ include_epsillon[i] = true;
+
+ // Find productions contained epsillon.
+ while (true)
+ {
+ var change = false;
+
+ for (int i = 0; i < production_rules.Count; i++)
+ for (int j = 0; j < production_rules[i].sub_productions.Count; j++)
+ if (production_rules[i].sub_productions[j].All(x => include_epsillon[x.index]))
+ {
+ if (include_epsillon[i] == false)
+ {
+ include_epsillon[i] = true;
+ change = true;
+ }
+ break;
+ }
+
+ if (!change) break;
+ }
+ // ---------------------------------------------------------
+
+ // (state_index, (production_rule_index, sub_productions_pos, dot_position, (lookahead))
+ var states = new Dictionary>>>();
+ // (state_specify, state_index)
+ var state_index = new Dictionary();
+ // (state_index, (state_item_index, (handle_position, parent_state_index, parent_state_item_index)))
+ var pred = new Dictionary>>>();
+ // (from_state_index, (when_state_index, to_state_index))
+ var goto_table = new List>>>();
+ // (state_index, (shift_what, state_index))
+ shift_info = new Dictionary>>();
+ // (state_index, (reduce_what, production_rule_index, sub_productions_pos))
+ reduce_info = new Dictionary>>();
+ var index_count = 0;
+
+ // -------------------- Put first eater -------------------
+ var first_l = closure(0, 0, 0).Select(x => new Tuple>(x.Item1, x.Item2, x.Item3, new HashSet())).ToList();
+ state_index.Add(l2sl(first_l, 1), 0);
+ states.Add(0, first_l);
+ // --------------------------------------------------------
+
+ // Create all LR states
+ // (states)
+ var q = new Queue();
+ q.Enqueue(index_count++);
+ while (q.Count != 0)
+ {
+ var p = q.Dequeue();
+
+ // Collect goto
+ // (state_index, (production_rule_index, sub_productions_pos, dot_position, lookahead))
+ var gotos = new Dictionary>>>();
+ // (state_index, kernel_count)
+ var kernel_cnt = new Dictionary();
+ // (state_index, (handle_position, parent_state_item_index))
+ var ppred = new Dictionary>>();
+ for (int i = 0; i < states[p].Count; i++)
+ {
+ var transition = states[p][i];
+ if (production_rules[transition.Item1].sub_productions[transition.Item2].Count > transition.Item3)
+ {
+ var pi = production_rules[transition.Item1].sub_productions[transition.Item2][transition.Item3].index;
+ if (!gotos.ContainsKey(pi))
+ {
+ gotos.Add(pi, new List>>());
+ kernel_cnt.Add(pi, 0);
+ ppred.Add(pi, new List>());
+ }
+ gotos[pi].Add(new Tuple>(transition.Item1, transition.Item2, transition.Item3 + 1, new HashSet()));
+ kernel_cnt[pi] = kernel_cnt[pi] + 1;
+ ppred[pi].Add(new Tuple(transition.Item3, i));
+ }
+ }
+
+ // Populate closures
+ foreach (var goto_unit in gotos)
+ {
+ var set = new HashSet();
+ // Push exists transitions
+ foreach (var psd in goto_unit.Value)
+ set.Add(i2s(psd.Item1, psd.Item2, psd.Item3));
+ // Find all transitions
+ var new_trans = new List>>();
+ foreach (var psd in goto_unit.Value)
+ {
+ if (production_rules[psd.Item1].sub_productions[psd.Item2].Count == psd.Item3) continue;
+ if (production_rules[psd.Item1].sub_productions[psd.Item2][psd.Item3].isterminal) continue;
+ var first_nt = closure(psd.Item1, psd.Item2, psd.Item3);
+ foreach (var nts in first_nt)
+ if (!set.Contains(t2s(nts)))
+ {
+ new_trans.Add(new Tuple>(nts.Item1, nts.Item2, nts.Item3, new HashSet()));
+ set.Add(t2s(nts));
+ }
+ }
+ goto_unit.Value.AddRange(new_trans);
+ }
+
+ // Build goto transitions ignore terminal, non-terminal anywhere
+ var index_list = new List>();
+ foreach (var pp in gotos)
+ {
+ var kernels = kernel_cnt[pp.Key];
+ var hash = l2sl(pp.Value, kernels);
+ if (!state_index.ContainsKey(hash))
+ {
+ states.Add(index_count, pp.Value);
+ state_index.Add(hash, index_count);
+
+ if (!pred.ContainsKey(index_count))
+ pred.Add(index_count, new Dictionary>>());
+ for (int i = 0; i < kernels; i++)
+ {
+ if (!pred[index_count].ContainsKey(i))
+ pred[index_count].Add(i, new List>());
+ pred[index_count][i].Add(new Tuple(ppred[pp.Key][i].Item1, p, ppred[pp.Key][i].Item2));
+ }
+
+ q.Enqueue(index_count++);
+ }
+ else
+ {
+ var index = state_index[hash];
+ if (!pred.ContainsKey(index))
+ pred.Add(index, new Dictionary>>());
+ for (int i = 0; i < kernels; i++)
+ {
+ if (!pred[index].ContainsKey(i))
+ pred[index].Add(i, new List>());
+ pred[index][i].Add(new Tuple(ppred[pp.Key][i].Item1, p, ppred[pp.Key][i].Item2));
+ }
+ }
+ index_list.Add(new Tuple(pp.Key, state_index[hash]));
+ }
+
+ goto_table.Add(new Tuple>>(p, index_list));
+ }
+
+#if false
+ print_header("LR0 Items");
+ foreach (var s in states)
+ print_states(s.Key, s.Value);
+#endif
+
+ // -------------------- Fill Lookahead -------------------
+
+ // Insert EOP (End of Parsing marker)
+ states[0][0].Item4.Add(-1);
+
+ // Find all reduceable LR(0) states item and fill lookahead
+ while (true)
+ {
+ lookahead_change = false;
+ foreach (var state in states)
+ {
+ for (int i = 0; i < state.Value.Count; i++)
+ {
+ // Find the state that the handle is declared.
+ // If blew is declared,
+ // A -> abc.
+ // then trace location of handle definition recursive.
+ // A -> ab.c
+ // A -> a.bc
+ // A -> .abc
+ var lrs = state.Value[i];
+ if (production_rules[lrs.Item1].sub_productions[lrs.Item2].Count == lrs.Item3)
+ {
+ fill_lookahead(FIRST, include_epsillon, states, pred, state.Key, i);
+ }
+ }
+ }
+
+ if (!lookahead_change)
+ break;
+ }
+
+ //var visit = Enumerable.Repeat(false, goto_table.Count);
+ //var indegree_count = new Dictionary();
+ //for (int i = 0; i < goto_table.Count; i++)
+ // for (int j = 0; j < goto_table[i].Item2.Count; j++)
+ // {
+ // var from = goto_table[i].Item2[j].Item2;
+ // if (!indegree_count.ContainsKey(from))
+ // indegree_count.Add(from, 0);
+ // indegree_count[from] = from + 1;
+ // }
+
+ // -------------------------------------------------------
+
+#if true
+ print_header("LALR STATES");
+ foreach (var s in states)
+ print_states(s.Key, s.Value);
+#endif
+
+ var occurred_conflict = false;
+
+ // ------------- Find Shift-Reduce Conflict ------------
+ foreach (var state in states)
+ {
+ // (shift_what, state_index)
+ var small_shift_info = new List>();
+ // (reduce_what, production_rule_index, sub_productions_pos)
+ var small_reduce_info = new List>();
+
+ // Fill Shift Info
+ foreach (var pp in goto_table[state.Key].Item2)
+ small_shift_info.Add(new Tuple(pp.Item1, pp.Item2));
+
+ // Fill Reduce Info
+ foreach (var transition in state.Value)
+ if (production_rules[transition.Item1].sub_productions[transition.Item2].Count == transition.Item3)
+ {
+ foreach (var term in transition.Item4)
+ small_reduce_info.Add(new Tuple(term, transition.Item1, transition.Item2));
+ }
+
+ // Conflict Check
+ // (shift_what, small_shift_info_index)
+ var shift_tokens = new Dictionary();
+ for (int i = 0; i < small_shift_info.Count; i++)
+ shift_tokens.Add(small_shift_info[i].Item1, i);
+ var completes = new HashSet();
+
+ foreach (var tuple in small_reduce_info)
+ {
+ if (completes.Contains(tuple.Item1))
+ {
+ // It's already added so do not have to work anymore.
+ continue;
+ }
+
+ if (shift_tokens.ContainsKey(tuple.Item1))
+ {
+#if false
+ print_header("SHIFT-REDUCE CONFLICTS");
+ GlobalPrinter.Append($"Shift-Reduce Conflict! {(tuple.Item1 == -1 ? "$" : production_rules[tuple.Item1].production_name)}\r\n");
+ GlobalPrinter.Append($"States: {ms.Key} {small_shift_info[shift_tokens[tuple.Item1]].Item2}\r\n");
+ print_states(ms.Key, states[ms.Key]);
+ print_states(small_shift_info[shift_tokens[tuple.Item1]].Item2, states[small_shift_info[shift_tokens[tuple.Item1]].Item2]);
+#endif
+ Tuple p1 = null, p2 = null;
+
+#if DEBUG
+ string mm = "";
+#endif
+ try
+ {
+ var pp = get_first_on_right_terminal(production_rules[tuple.Item2], tuple.Item3);
+ if (shift_reduce_conflict_solve.ContainsKey(pp.index))
+ p1 = shift_reduce_conflict_solve[pp.index];
+ }
+ catch (Exception e)
+ {
+#if !DEBUG
+ GlobalPrinter.Append(e.Message + "\r\n");
+#else
+ mm = e.Message + "\r\n";
+#endif
+ }
+
+ if (shift_reduce_conflict_solve.ContainsKey(tuple.Item1))
+ p2 = shift_reduce_conflict_solve[tuple.Item1];
+
+ if (shift_reduce_conflict_solve_with_production_rule.ContainsKey(tuple.Item2))
+ if (shift_reduce_conflict_solve_with_production_rule[tuple.Item2].ContainsKey(tuple.Item3))
+ p1 = shift_reduce_conflict_solve_with_production_rule[tuple.Item2][tuple.Item3];
+
+ //if (shift_reduce_conflict_solve_with_production_rule.ContainsKey(states[tuple.Item1][0].Item1))
+ // if (shift_reduce_conflict_solve_with_production_rule[states[tuple.Item1][0].Item1].ContainsKey(states[tuple.Item1][0].Item2))
+ // p2 = shift_reduce_conflict_solve_with_production_rule[states[tuple.Item1][0].Item1][states[tuple.Item1][0].Item2];
+
+ if (p1 == null || p2 == null)
+ {
+#if DEBUG
+ print_header("SHIFT-REDUCE CONFLICTS");
+ GlobalPrinter.Append($"Shift-Reduce Conflict! {(tuple.Item1 == -1 ? "$" : production_rules[tuple.Item1].production_name)}\r\n");
+ GlobalPrinter.Append($"States: {state.Key} {small_shift_info[shift_tokens[tuple.Item1]].Item2}\r\n");
+ print_states(state.Key, state.Value);
+ print_states(small_shift_info[shift_tokens[tuple.Item1]].Item2, states[small_shift_info[shift_tokens[tuple.Item1]].Item2]);
+ if (mm != "")
+ GlobalPrinter.Append(mm);
+#endif
+ occurred_conflict = true;
+ continue;
+ }
+
+ if (p1.Item1 < p2.Item1 || (p1.Item1 == p2.Item1 && p1.Item2))
+ {
+ // Reduce
+ if (!reduce_info.ContainsKey(state.Key))
+ reduce_info.Add(state.Key, new List>());
+ reduce_info[state.Key].Add(new Tuple(tuple.Item1, tuple.Item2, tuple.Item3));
+ }
+ else
+ {
+ // Shift
+ if (!shift_info.ContainsKey(state.Key))
+ shift_info.Add(state.Key, new List>());
+ shift_info[state.Key].Add(new Tuple(tuple.Item1, small_shift_info[shift_tokens[tuple.Item1]].Item2));
+ }
+
+ completes.Add(tuple.Item1);
+ }
+ else
+ {
+ // Just add reduce item
+ if (!reduce_info.ContainsKey(state.Key))
+ reduce_info.Add(state.Key, new List>());
+ reduce_info[state.Key].Add(new Tuple(tuple.Item1, tuple.Item2, tuple.Item3));
+
+ completes.Add(tuple.Item1);
+ }
+ }
+
+ foreach (var pair in shift_tokens)
+ {
+ if (completes.Contains(pair.Key)) continue;
+ var shift = small_shift_info[pair.Value];
+ if (!shift_info.ContainsKey(state.Key))
+ shift_info.Add(state.Key, new List>());
+ shift_info[state.Key].Add(new Tuple(shift.Item1, shift.Item2));
+ }
+ }
+ // -----------------------------------------------------
+
+ if (occurred_conflict)
+ throw new Exception("Specify the rules to resolve Shift-Reduce Conflict!");
+
+ number_of_states = states.Count;
+ }
+
+ #endregion
+
+ #region Printer
+
+ public void PrintProductionRules()
+ {
+ print_header("PRODUCTION RULES");
+ int count = 1;
+ var builder = new StringBuilder();
+ foreach (var pp in production_rules)
+ {
+ foreach (var p in pp.sub_productions)
+ {
+ builder.Append($"{(count++).ToString().PadLeft(4)}: ");
+ builder.Append($"{pp.production_name.ToString().PadLeft(10)} -> ");
+
+ for (int i = 0; i < p.Count; i++)
+ {
+ builder.Append(p[i].production_name + " ");
+ }
+
+ builder.Append("\r\n");
+ }
+ }
+ GlobalPrinter.Append(builder.ToString());
+ }
+
+ ///
+ /// 파싱 테이블을 집합형태로 출력합니다.
+ ///
+ public void PrintStates()
+ {
+ print_header("FINAL STATES");
+ for (int i = 0; i < number_of_states; i++)
+ {
+ var builder = new StringBuilder();
+ var x = $"I{i} => ";
+ builder.Append(x);
+ if (shift_info.ContainsKey(i))
+ {
+ builder.Append("SHIFT{" + string.Join(",", shift_info[i].Select(y => $"({production_rules[y.Item1].production_name},I{y.Item2})")) + "}");
+ if (reduce_info.ContainsKey(i))
+ builder.Append("\r\n" + "".PadLeft(x.Length) + "REDUCE{" + string.Join(",", reduce_info[i].Select(y => $"({(y.Item1 == -1 ? "$" : production_rules[y.Item1].production_name)},{(y.Item2 == 0 ? "accept" : production_rules[y.Item2].production_name)},{y.Item3})")) + "}");
+ }
+ else if (reduce_info.ContainsKey(i))
+ builder.Append("REDUCE{" + string.Join(",", reduce_info[i].Select(y => $"({(y.Item1 == -1 ? "$" : production_rules[y.Item1].production_name)},{(y.Item2 == 0 ? "accept" : production_rules[y.Item2].production_name)},{y.Item3})")) + "}");
+ GlobalPrinter.Append(builder.ToString() + "\r\n");
+ }
+ }
+
+ ///
+ /// 파싱테이블을 테이블 형태로 출력합니다.
+ ///
+ public void PrintTable()
+ {
+ var production_mapping = new List>();
+ var pm_count = 0;
+
+ foreach (var pr in production_rules)
+ {
+ var pm = new List();
+ foreach (var sub_pr in pr.sub_productions)
+ pm.Add(pm_count++);
+ production_mapping.Add(pm);
+ }
+
+ var builder = new StringBuilder();
+
+ var tokens = new Dictionary();
+ var max_len = 0;
+ foreach (var pp in production_rules)
+ if (pp.isterminal)
+ tokens.Add(tokens.Count, pp.index);
+ tokens.Add(tokens.Count, -1);
+ foreach (var pp in production_rules)
+ {
+ if (pp.index == 0) continue;
+ if (!pp.isterminal)
+ tokens.Add(tokens.Count, pp.index);
+ max_len = Math.Max(max_len, pp.production_name.Length);
+ }
+
+ var split_line = "+" + new string('*', production_rules.Count + 1).Replace("*", new string('-', max_len + 2) + "+") + "\r\n";
+ builder.Append(split_line);
+
+ // print production rule
+ builder.Append('|' + "".PadLeft(max_len + 2) + '|');
+ for (int i = 0; i < tokens.Count; i++)
+ {
+ builder.Append(" " + (tokens[i] == -1 ? "$" : production_rules[tokens[i]].production_name).PadLeft(max_len) + " ");
+ builder.Append('|');
+ }
+ builder.Append("\r\n");
+ builder.Append(split_line);
+
+ // print states
+ for (int i = 0; i < number_of_states; i++)
+ {
+ builder.Append('|' + " " + $"{i}".PadLeft(max_len - 2) + " |");
+
+ // (what, (state_index, isshift))
+ var sr_info = new Dictionary>();
+
+ if (shift_info.ContainsKey(i))
+ {
+ foreach (var si in shift_info[i])
+ if (!sr_info.ContainsKey(si.Item1))
+ sr_info.Add(si.Item1, new Tuple(si.Item2, true));
+ }
+ if (reduce_info.ContainsKey(i))
+ {
+ foreach (var ri in reduce_info[i])
+ if (!sr_info.ContainsKey(ri.Item1))
+ sr_info.Add(ri.Item1, new Tuple(production_mapping[ri.Item2][ri.Item3], false));
+ }
+
+ for (int j = 0; j < tokens.Count; j++)
+ {
+ var k = tokens[j];
+ if (sr_info.ContainsKey(k))
+ {
+ var ss = "";
+ if (sr_info[k].Item2)
+ {
+ if (production_rules[k].isterminal)
+ ss += "s" + sr_info[k].Item1;
+ else
+ ss = sr_info[k].Item1.ToString();
+ }
+ else
+ {
+ if (sr_info[k].Item1 == 0)
+ ss += "acc";
+ else
+ ss += "r" + sr_info[k].Item1;
+ }
+ builder.Append(" " + ss.PadLeft(max_len) + " |");
+ }
+ else
+ {
+ builder.Append("".PadLeft(max_len + 2) + "|");
+ }
+ }
+
+ builder.Append("\r\n");
+ }
+ builder.Append(split_line);
+
+ print_header("PARSING TABLE");
+ GlobalPrinter.Append(builder.ToString() + "\r\n");
+ }
+
+ #endregion
+
+ #region FIRST
+
+ ///
+ /// Calculate FIRST only Terminals
+ ///
+ ///
+ ///
+ private HashSet first_terminals(int index)
+ {
+ var result = new HashSet();
+ var q = new Queue();
+ var visit = new List();
+ visit.AddRange(Enumerable.Repeat(false, production_rules.Count));
+ q.Enqueue(index);
+
+ while (q.Count != 0)
+ {
+ var p = q.Dequeue();
+ if (p < 0 || visit[p]) continue;
+ visit[p] = true;
+
+ if (p < 0 || production_rules[p].isterminal)
+ result.Add(p);
+ else
+ {
+ foreach (var pp in production_rules[p].sub_productions.Where(x => x.Count > 0))
+ {
+ foreach (var ppp in pp)
+ {
+ q.Enqueue(ppp.index);
+ if (ppp.sub_productions.All(x => x.Count != 0))
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Calculate FIRST only Non-Terminals
+ ///
+ ///
+ ///
+ private List> first_nonterminals(int production_rule_index)
+ {
+ // (production_rule_index, sub_productions_pos, dot_position)
+ var first_l = new List>();
+ // (production_rule_index, sub_productions_pos)
+ var first_q = new Queue>();
+ // (production_rule_index, (sub_productions_pos))
+ var first_visit = new Dictionary>();
+ first_q.Enqueue(new Tuple(production_rule_index, 0));
+ for (int j = 0; j < production_rules[production_rule_index].sub_productions.Count; j++)
+ first_q.Enqueue(new Tuple(production_rule_index, j));
+ // Get all of starts node FIRST non-terminals
+ while (first_q.Count != 0)
+ {
+ var t = first_q.Dequeue();
+ if (first_visit.ContainsKey(t.Item1) && first_visit[t.Item1].Contains(t.Item2)) continue;
+ if (!first_visit.ContainsKey(t.Item1)) first_visit.Add(t.Item1, new HashSet());
+ first_visit[t.Item1].Add(t.Item2);
+ first_l.Add(new Tuple(t.Item1, t.Item2, 0));
+ for (int i = 0; i < production_rules[t.Item1].sub_productions.Count; i++)
+ {
+ var sub_pr = production_rules[t.Item1].sub_productions[i];
+ if (sub_pr.Count > 0 && sub_pr[0].isterminal == false)
+ for (int j = 0; j < production_rules[sub_pr[0].index].sub_productions.Count; j++)
+ first_q.Enqueue(new Tuple(sub_pr[0].index, j));
+ }
+ }
+ return first_l;
+ }
+
+ #endregion
+
+ #region FOLLOW
+
+ ///
+ /// Get FOLLOW set for all production-rules
+ ///
+ ///
+ ///
+ private List> follow_terminals(List> FIRST)
+ {
+ var FOLLOW = new List>();
+ for (int i = 0; i < production_rules.Count; i++)
+ FOLLOW.Add(new HashSet());
+ FOLLOW[0].Add(-1); // -1: Sentinel
+
+ // 1. B -> a A b, Add FIRST(b) to FOLLOW(A)
+ for (int i = 0; i < production_rules.Count; i++)
+ if (!production_rules[i].isterminal)
+ foreach (var rule in production_rules[i].sub_productions)
+ for (int j = 0; j < rule.Count - 1; j++)
+ if (rule[j].isterminal == false || rule[j + 1].isterminal)
+ foreach (var r in FIRST[rule[j + 1].index])
+ FOLLOW[rule[j].index].Add(r);
+
+ // 2. B -> a A b and empty -> FIRST(b), Add FOLLOW(B) to FOLLOW(A)
+ for (int i = 0; i < production_rules.Count; i++)
+ if (!production_rules[i].isterminal)
+ foreach (var rule in production_rules[i].sub_productions)
+ if (rule.Count > 2 && rule[rule.Count - 2].isterminal == false && FIRST[rule.Last().index].Contains(EmptyString.index))
+ foreach (var r in FOLLOW[i])
+ FOLLOW[rule[rule.Count - 2].index].Add(r);
+
+ // 3. B -> a A, Add FOLLOW(B) to FOLLOW(A)
+ for (int i = 0; i < production_rules.Count; i++)
+ if (!production_rules[i].isterminal)
+ foreach (var rule in production_rules[i].sub_productions)
+ if (rule.Count > 0 && rule.Last().isterminal == false)
+ foreach (var r in FOLLOW[i])
+ if (rule.Last().index > 0)
+ FOLLOW[rule.Last().index].Add(r);
+
+ return FOLLOW;
+ }
+
+ #endregion
+
+ #region Closure with Lookahead
+
+ ///
+ /// Get lookahead states item with first item's closure
+ /// This function is used in first_with_lookahead function.
+ /// -1: Sentinel lookahead
+ ///
+ ///
+ ///
+ private List>> lookahead_with_first(int production_rule_index, int sub_production, int sub_production_index, HashSet pred)
+ {
+ // (production_rule_index, sub_productions_pos, dot_position, (lookahead))
+ var states = new List>>();
+ // (production_rule_index, (sub_productions_pos))
+ var first_visit = new Dictionary>();
+ states.Add(new Tuple>(production_rule_index, sub_production, sub_production_index, pred));
+ if (production_rule_index == 0 && sub_production == 0 && sub_production_index == 0)
+ pred.Add(-1); // Push sentinel
+ if (production_rules[production_rule_index].sub_productions[sub_production].Count > sub_production_index)
+ {
+ if (!production_rules[production_rule_index].sub_productions[sub_production][sub_production_index].isterminal)
+ {
+ var index_populate = production_rules[production_rule_index].sub_productions[sub_production][sub_production_index].index;
+ if (production_rules[production_rule_index].sub_productions[sub_production].Count <= sub_production_index + 1)
+ {
+ for (int i = 0; i < production_rules[index_populate].sub_productions.Count; i++)
+ states.Add(new Tuple>(index_populate, i, 0, new HashSet(pred)));
+ }
+ else
+ {
+ var first_lookahead = first_terminals(production_rules[production_rule_index].sub_productions[sub_production][sub_production_index + 1].index);
+ for (int i = 0; i < production_rules[index_populate].sub_productions.Count; i++)
+ states.Add(new Tuple>(index_populate, i, 0, new HashSet(first_lookahead)));
+ }
+ }
+ }
+ return states;
+ }
+
+ ///
+ /// Get FIRST items with lookahead (Build specific states completely)
+ ///
+ /// TODO: Fix issues #4:first_terminals
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private List>> first_with_lookahead(int production_rule_index, int sub_production, int sub_production_index, HashSet pred)
+ {
+ // (production_rule_index, sub_productions_pos, dot_position, (lookahead))
+ var states = new List>>();
+ // (production_rule_index + sub_productions_pos + dot_position), (states_index)
+ var states_prefix = new Dictionary();
+
+ var q = new Queue>>>();
+ q.Enqueue(lookahead_with_first(production_rule_index, sub_production, sub_production_index, pred));
+ while (q.Count != 0)
+ {
+ var ll = q.Dequeue();
+ foreach (var e in ll)
+ {
+ var ii = i2s(e.Item1, e.Item2, e.Item3);
+ if (!states_prefix.ContainsKey(ii))
+ {
+ states_prefix.Add(ii, states.Count);
+ states.Add(e);
+ q.Enqueue(lookahead_with_first(e.Item1, e.Item2, e.Item3, e.Item4));
+ }
+ else
+ {
+ foreach (var hse in e.Item4)
+ states[states_prefix[ii]].Item4.Add(hse);
+ }
+ }
+ }
+
+ // (production_rule_index + sub_productions_pos + dot_position), (states_index)
+ var states_prefix2 = new Dictionary();
+ var states_count = 0;
+ bool change = false;
+
+ do
+ {
+ change = false;
+ q.Enqueue(lookahead_with_first(production_rule_index, sub_production, sub_production_index, pred));
+ while (q.Count != 0)
+ {
+ var ll = q.Dequeue();
+ foreach (var e in ll)
+ {
+ var ii = i2s(e.Item1, e.Item2, e.Item3);
+ if (!states_prefix2.ContainsKey(ii))
+ {
+ states_prefix2.Add(ii, states_count);
+ foreach (var hse in e.Item4)
+ if (!states[states_prefix[ii]].Item4.Contains(hse))
+ {
+ change = true;
+ states[states_prefix[ii]].Item4.Add(hse);
+ }
+ q.Enqueue(lookahead_with_first(e.Item1, e.Item2, e.Item3, states[states_count].Item4));
+ states_count++;
+ }
+ else
+ {
+ foreach (var hse in e.Item4)
+ if (!states[states_prefix[ii]].Item4.Contains(hse))
+ {
+ change = true;
+ states[states_prefix[ii]].Item4.Add(hse);
+ }
+ }
+ }
+ }
+ } while (change);
+
+ return states;
+ }
+
+ #endregion
+
+ #region Closure
+
+ ///
+ /// Get states item with first item's closure
+ /// This function is used in closure function.
+ /// -1: Sentinel lookahead
+ ///
+ ///
+ ///
+ private List> closure_first(int production_rule_index, int sub_production, int sub_production_index)
+ {
+ // (production_rule_index, sub_productions_pos, dot_position, (lookahead))
+ var states = new List>();
+ states.Add(new Tuple(production_rule_index, sub_production, sub_production_index));
+ if (production_rules[production_rule_index].sub_productions[sub_production].Count > sub_production_index)
+ {
+ if (!production_rules[production_rule_index].sub_productions[sub_production][sub_production_index].isterminal)
+ {
+ var index_populate = production_rules[production_rule_index].sub_productions[sub_production][sub_production_index].index;
+ for (int i = 0; i < production_rules[index_populate].sub_productions.Count; i++)
+ states.Add(new Tuple(index_populate, i, 0));
+ }
+ }
+ return states;
+ }
+
+ ///
+ /// Get CLOSURE items (Build specific states completely)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private List> closure(int production_rule_index, int sub_production, int sub_production_index)
+ {
+ // (production_rule_index, sub_productions_pos, dot_position, (lookahead))
+ var states = new List>();
+ // (production_rule_index + sub_productions_pos + dot_position), (states_index)
+ var states_prefix = new Dictionary();
+
+ var q = new Queue>>();
+ q.Enqueue(closure_first(production_rule_index, sub_production, sub_production_index));
+ while (q.Count != 0)
+ {
+ var ll = q.Dequeue();
+ foreach (var e in ll)
+ {
+ var ii = i2s(e.Item1, e.Item2, e.Item3);
+ if (!states_prefix.ContainsKey(ii))
+ {
+ states_prefix.Add(ii, states.Count);
+ states.Add(e);
+ q.Enqueue(closure_first(e.Item1, e.Item2, e.Item3));
+ }
+ }
+ }
+
+ // (production_rule_index + sub_productions_pos + dot_position), (states_index)
+ var states_prefix2 = new Dictionary();
+ var states_count = 0;
+
+ q.Enqueue(closure_first(production_rule_index, sub_production, sub_production_index));
+ while (q.Count != 0)
+ {
+ var ll = q.Dequeue();
+ foreach (var e in ll)
+ {
+ var ii = i2s(e.Item1, e.Item2, e.Item3);
+ if (!states_prefix2.ContainsKey(ii))
+ {
+ states_prefix2.Add(ii, states_count);
+ q.Enqueue(closure_first(e.Item1, e.Item2, e.Item3));
+ states_count++;
+ }
+ }
+ }
+
+ return states;
+ }
+
+ #endregion
+
+ #region SCC
+
+ ///
+ /// Determine group using tarjan's strongly connected components algorithm.
+ ///
+ ///
+ ///
+ private Dictionary determine_group(Dictionary> degree)
+ {
+ return null;
+ }
+
+ ///
+ /// Returns the graph traversal rule and SCC information
+ ///
+ ///
+ ///
+ private Tuple, Dictionary> how_to_visit(
+ // (from_state_index, (when_state_index, to_state_index))
+ List>>> goto_table)
+ {
+ // to edge
+ var degree = new Dictionary>();
+ for (int i = 0; i < goto_table.Count; i++)
+ {
+ degree.Add(i, new List());
+ for (int j = 0; j < goto_table[i].Item2.Count; i++)
+ degree[i].Add(goto_table[i].Item2[j].Item2);
+ }
+
+ return null;
+ }
+
+ #endregion
+
+ #region Lookahead
+
+ ///