Prolog Interpreter

Keywords: Xamarin.Forms, Prolog, C#Prolog, CSProlog, PCL Storage, Command Prompt


I didn't update this blog for a while, but I came to want to enjoy Prolog programming and I re-started application development.  First of all, I post an application, Prolog Interpreter, that I almost developed before.  The Prolog Interpreter App has been developed with a Xamarin Library, CSProlog, based on the Command Prompt App that I posted before.


The source code is here.

Since MainPage.xaml, MainPage.xaml.cs, ComInterpreter.cs, CommandExecute.cs, PCLStorage.cs are the same as the ones in Command Prompt App, I skip their description and introduce Prolog.cs beriefly below.

I developed Prolog.cs with reference to some sample programs.  Obviously, one of the NuGet packages, CSProlog, are added to this project.

Prolog.cs
//using System.Text;

//#define SystemIO
#define PCLStorage

// #define iOS

using System.Collections.Generic;
using System.Linq;

#if SystemIO
    using System.IO;
#elif PCLStorage
    using System.Threading.Tasks;   
    using PCLStorage;
#endif

using Xamarin.Forms;


namespace Prolog
{
    public partial class MainPage : ContentPage
    {
        // Create Prolog Engine
        PrologEngine prolog
            = new PrologEngine(persistentCommandHistory: false);

        bool RunProlog = false;
        bool RunUserSetClause = false;
        string UserSetClauses = "";

       
        /*
        class Clause
        {
            public string Predicate { get; set; }
            private bool fact;
            public bool Fact
            {
                get { return !this.rule; }
                set
                {
                    if (this.fact != value) this.fact = value;
                }
            }

            private bool rule;
            public bool Rule
            {
                get { return !this.fact; }
                set
                {
                    if (this.rule != value) this.rule = value;
                }
            }
        }
        */
        //List<Clause> Program = new List<Clause>();
       

        class Solution
        {
            public string Name { get; set; }
            public string Type { get; set; }
            //public ITermNode Value { get; set; }
            public string Value { get; set; }
            public string Note { get; set; }
        }


        // Prolog Interpreter:
        //    Identify Input Command and Execute it
#if SystemIO
        void PrologInterpreter(string command)
#elif PCLStorage
        async void PrologInterpreter(string command)
#endif
        {
            string result = "";
            string com = "";
            List<Solution> solutions = new List<Solution>();

            // Get the first character of the command
// #if iOS
            if (command != null)
// #else // else if UWP
//             if(command != "")
// #endif
                com = command.Substring(0, 1);

            // Identify the command from the three characters           
            switch (com)
            {
                case "":
                case null:
                    AddPrompt(GetPromptText());
                    return;

                case "l":   // List Segments of the current folder
                    if (command == "ls.")
                    {
                        result = ls();
                        break;
                    }
                    else goto default;

                case "[":   // Load Program
#if SystemIO
                    result = SetProgram(command);
#elif PCLStorage
                    result = await SetProgram(command);
#endif
                    break;


                case "h":   // Exit Prolog Interpreter
                    if (command == "halt.")
                    {
                        RunProlog = false;
                        prolog.Reset();                       
                        result = "\n";
                        //System.Diagnostics.Process.GetCurrentProcess().CloseMainWindow();
                        break;
                    }
                    else goto default;
                    //{
                    //    result = "Command Invalid";
                    //}
                    //break;

                case "r":   // Reset Prolog Engine
                    if (command == "reset.")
                    {
                        prolog.Reset();
                        result = "\n";
                        break;
                    }
                    else goto default;
                    //{
                    //    result = "Command Invalid";
                    //}
                    //break;


                default:    // Query Input
                    solutions = GetSolutions(prolog, command);
                    result = SolutionsString(solutions);
                    break;
            }

            // Display the Command Execute Result following the Command Line
            Console.Children.Add(new Label() { Text = result });

            // Store the result
            CommandLines.Last().Results = result;

            // Add a new Command Line
            AddPrompt(GetPromptText());
        }


        // List Segments of the current folder
        string ls()
        {
            string result = "";

#if SystemIO
            string[] files =
                Directory.GetFiles(WorkingDir, "*.*", SearchOption.TopDirectoryOnly);
            int WorkingDirTextLength = WorkingDir.Length;

            foreach (string file in files)
                result += (file.Substring(WorkingDirTextLength) + "\n");
#elif PCLStorage
            Folder folder = CurrentFolder;

            foreach (Folder subfolder in folder.SubFolders)
                result += string.Format("<DIR>  {0}\n", subfolder.Name);

            foreach (File file in folder.Files)
                result += file.Name + "\n";
#endif

            return result;
        }



        // Load Prolog program
#if SystemIO
        string SetProgram(string command)
#elif PCLStorage
        async Task<string> SetProgram(string command)
#endif
        {
            string result = "";

            int length = command.Length;
            string file = command.Substring(1, length - 3);

            if (command.Substring(length - 2) != "].")
            {
                result = "Input Invalid";
            }
            else if (file == "user")    // [user].
            {
                RunUserSetClause = true;
                UserSetClauses = "";
                result = "User Set Clause Mode";
            }
            else
            {
#if SystemIO
    #if iOS
                string code = File.ReadAllText(WorkingDir + file);
    #else
                string code = File.ReadAllText(WorkingDir + '\\' + file);
    #endif               
#elif PCLStorage
                IFile iFile = await IGetFile(file, CurrentFolder);
                string code = await IReadFile(iFile);
#endif
                result = code;

                // Set all clauses in the code
                if (SetClause(prolog, code))
                    StatusLabel.Text = "Set Clauses";

            }

            return result;
        }


        // Set Clause to the prolog engine
        bool SetClause(PrologEngine plEngine, string code, bool reset = true,
                        string codeTitle = null)
        {
            bool error = false;

            if (reset) plEngine.Reset();

            // If no syntax error, consult the code to the prolog engine
            if (SyntaxCheck(code))
                plEngine.ConsultFromString(code, codeTitle);

            else error = true;

            return !error;
        }


        // Prolog Syntax Checker
        bool SyntaxCheck(string code)
        {
            bool error = false;

            return !error;
        }



        // Get all solutions of the input query
        List<Solution> GetSolutions(PrologEngine plEngine, string query)
        {
            List<Solution> solutions = new List<Solution>();
            Solution solution = new Solution();

            // If string is in the query, convert to list
            query = StringToList(query);
            Label2.Text = query;

            // Set Query
            if (SyntaxCheck(query))
            {
                plEngine.Query = query;
            }
            else
            {
                solution.Note = "ERROR";
                solutions.Add(solution);
                return solutions;
            }


            // Get All Solutions
            foreach (PrologEngine.ISolution s in plEngine.SolutionIterator)
            {
                // The No of Solutions is ZERO, the solution is True or False
                if (s.VarValuesIterator.Count() == 0)
                {
                    solution.Note = "ZERO";
                    solution.Name = s.Solved.ToString();
                    solutions.Add(solution);
                    break;
                }

                foreach (PrologEngine.IVarValue v in s.VarValuesIterator)
                {
                    solutions.Add(new Solution()
                    {
                        Name = v.Name,
                        Type = v.DataType,
                        Value = v.Value.ToString(),
                        Note = ""
                    });
                }
                //if (s.IsLast) break;
            }
            return solutions;
        }


        // Convert string "aXb(Y)c:d-e" to list [a,'X', b,'(', 'Y', ')', c,':', d, '-', e]
        string StringToList(string str)
        {
            char[] chars = str.ToCharArray();
            bool DoubleQuote = false;
            string s = "";

            foreach (char c in chars)
            {
                if (c == '\"')  // find Double Quotation
                {
                    if (!DoubleQuote)
                    {
                        s += "[";
                        DoubleQuote = true;
                    }
                    else
                    {
                        s = s.Substring(0, s.Length - 1);
                        s += "]";
                        DoubleQuote = false;
                    }
                }
                else if (DoubleQuote)
                {
                    switch (c)
                    {
                        case '(':
                        case ')':
                        case '[':
                        case ']':
                        case ':':
                        case '-':
                        case ',':
                        case '_':
                        case '.':
                        case ' ':
                        case '%':
                            s += "\'" + c + "\'";
                            break;

                        default:
                            if (char.IsUpper(c))
                                s += ("\'" + c + "\'");
                            else s += c.ToString();
                            break;
                    }

                    s += ",";
                }
                else  // if(!DoubleQuote)
                {
                    s += c.ToString();
                }

            }

            return s;
        }


        /*
        // Convert result list [a,'X', b,'(', 'Y', ')', c,':', d, '-', e] to string "aXb(Y)c:d-e"
        string ListToString(string list)
        {
            char[] chars = list.ToCharArray();
            string s = "";

            foreach (char c in chars)
            {
                if (c == '[' || c == ']' || c == '\'' || c == ',') continue;

                s += c;
            }

            return s;
        }
        */


        // Make the solutions strings from the Solution List
        string SolutionsString(List<Solution> solutions)
        {
            string solution = "";

            foreach (Solution s in solutions)
            {
                if (s.Note == "ERROR")  // Error
                {
                    solution = s.Note + "\n";
                    break;
                }
                if (s.Note == "ZERO")   // Solution is True or False
                {
                    solution = s.Name + "\n";
                    break;
                }

                solution += string.Format("{0}({1}) = {2}\n",
                                                s.Name, s.Type, s.Value);
            }
            return solution;
        }



        // Identify User Input when [user] runs
        void UserSetClause(string clause)
        {
            string result = "";
            switch(clause)
            {
                case "exit.":
                    if (SetClause(prolog, UserSetClauses, false))
                        StatusLabel.Text = "Set Clauses";
                    RunUserSetClause = false;
                    result = "Set Clauses Sccessfully.\n";

                    // Display the Command Execute Result following the Command Line
                    Console.Children.Add(new Label() { Text = result });

                    break;

                default:
                    if(SyntaxCheck(clause))
                        UserSetClauses += (clause + "\n");
                    break;             
            }

            // Add a new Command Line
            AddPrompt(GetPromptText());
        }


    }
}



The command "Prolog" enable to move from the normal command prompt mode to the Prolog interpreter mode. The following are the commands in the Prolog interpreter mode:
  • ls.                List up the files in the current directory
  • [user].         Start the program user input mode
  • [file name].  Consult the Prolog file
  • reset.          Reset all the consulted Prolog program
  • halt.            Exit the Prolog interpreter mode

RunProlog and RunUserSetClause are bool variables to switch command input mode from the normal command interpreter to the Prolog interpreter and the program input mode by user.

In SetProgram method, the commands of "[user]." and "[file name]." are defined.  "[user]." command starts the program user input mode in which user input text are recorded as the program.  When the text "exit." is entered in the mode, all the recorded text are consulted and the input mode are returned to the Prolog interpreter mode.  The program consulting is run by the ConsultFromString method, one of the CSProlog libraries, in SetClause method.

After consulting program, when you enter a query on the Prolog interpreter, the GetSolutions and SolutionsString methods get the results for the query.

A movie showing this App running.  You can get the original movie file from here (in "movie" folder).



コメント

このブログの人気の投稿

Get the Color Code from an Image Pixel

PCL Storage (1)