├── .editorconfig ├── .gitignore ├── CSProlog.Core.Test ├── CSProlog.Core.Test.csproj └── PrologEngine.cs ├── CSProlog.sln ├── CSProlog ├── BaseTerm.cs ├── Bootstrap.cs ├── Builtins.cs ├── CSProlog.csproj ├── CSProlog.exe.config ├── CrossRefTable.cs ├── CsPrologHelp.resx ├── DerivedTerms.cs ├── DerivedTermsExotic.cs ├── Engine.cs ├── ExternalUsage.cs ├── IO.cs ├── Internet.cs ├── ListPatternTerm.cs ├── Miscellaneous.cs ├── Operator.cs ├── PG │ ├── BaseParser.cs │ ├── JSON.cs │ ├── JSON.grm │ ├── JsonParser.cs │ ├── JsonParserEx.cs │ ├── PL.cs │ ├── PL.grm │ ├── Parser.tpl │ ├── PrologParser.cs │ ├── PrologParserEx.cs │ ├── go.bat │ ├── jgo.bat │ └── pg4main.exe ├── PredDescr.cs ├── PredStorage.cs ├── SimpleDOMParser.cs ├── TermArithmetic.cs ├── TermArray.cs ├── TermNodeList.cs ├── TermSet.cs └── TokenSeqToTerm.cs ├── Docu ├── Covington-NL-book.zip ├── Edinburgh-style IO.doc ├── HistoryOfProlog.pdf ├── KdeBosschere-parser.zip ├── KdeBosschere-prolog.pdf ├── Standard Operators.doc └── prolog-digital.pdf ├── LICENSE ├── PL.NETcore ├── Main.cs └── PL.NETcore.csproj ├── PLd ├── Main.cs ├── PLd.csproj └── Properties │ └── AssemblyInfo.cs ├── PLw ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── PLw.csproj ├── PLw.sln ├── Program.cs └── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ ├── Settings.settings │ └── app.manifest ├── PLx ├── PLx.csproj ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── README (2007-2014).doc ├── README (2007-2014).pdf ├── README.md ├── README.txt └── appveyor.yml /.editorconfig: -------------------------------------------------------------------------------- 1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories 2 | root = true 3 | 4 | # C# files 5 | [*.cs] 6 | 7 | #### Core EditorConfig Options #### 8 | 9 | # Indentation and spacing 10 | indent_size = 4 11 | indent_style = space 12 | tab_width = 4 13 | 14 | # New line preferences 15 | end_of_line = crlf 16 | insert_final_newline = false 17 | 18 | #### .NET Coding Conventions #### 19 | 20 | # Organize usings 21 | dotnet_separate_import_directive_groups = false 22 | dotnet_sort_system_directives_first = true 23 | file_header_template = unset 24 | 25 | # this. and Me. preferences 26 | dotnet_style_qualification_for_event = false:silent 27 | dotnet_style_qualification_for_field = false:silent 28 | dotnet_style_qualification_for_method = false:silent 29 | dotnet_style_qualification_for_property = false:silent 30 | 31 | # Language keywords vs BCL types preferences 32 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 33 | dotnet_style_predefined_type_for_member_access = true:silent 34 | 35 | # Parentheses preferences 36 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 37 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 38 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 39 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 40 | 41 | # Modifier preferences 42 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 43 | 44 | # Expression-level preferences 45 | dotnet_style_coalesce_expression = true:suggestion 46 | dotnet_style_collection_initializer = true:suggestion 47 | dotnet_style_explicit_tuple_names = true:suggestion 48 | dotnet_style_null_propagation = true:suggestion 49 | dotnet_style_object_initializer = true:suggestion 50 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 51 | dotnet_style_prefer_auto_properties = true:silent 52 | dotnet_style_prefer_compound_assignment = true:suggestion 53 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 54 | dotnet_style_prefer_conditional_expression_over_return = true:silent 55 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 56 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 57 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 58 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 59 | dotnet_style_prefer_simplified_interpolation = true:suggestion 60 | 61 | # Field preferences 62 | dotnet_style_readonly_field = true:suggestion 63 | 64 | # Parameter preferences 65 | dotnet_code_quality_unused_parameters = all:suggestion 66 | 67 | #### C# Coding Conventions #### 68 | 69 | # var preferences 70 | csharp_style_var_elsewhere = false:silent 71 | csharp_style_var_for_built_in_types = false:silent 72 | csharp_style_var_when_type_is_apparent = false:silent 73 | 74 | # Expression-bodied members 75 | csharp_style_expression_bodied_accessors = true:silent 76 | csharp_style_expression_bodied_constructors = false:silent 77 | csharp_style_expression_bodied_indexers = true:silent 78 | csharp_style_expression_bodied_lambdas = true:silent 79 | csharp_style_expression_bodied_local_functions = false:silent 80 | csharp_style_expression_bodied_methods = false:silent 81 | csharp_style_expression_bodied_operators = false:silent 82 | csharp_style_expression_bodied_properties = true:silent 83 | 84 | # Pattern matching preferences 85 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 86 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 87 | csharp_style_prefer_switch_expression = true:suggestion 88 | 89 | # Null-checking preferences 90 | csharp_style_conditional_delegate_call = true:suggestion 91 | 92 | # Modifier preferences 93 | csharp_prefer_static_local_function = true:suggestion 94 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent 95 | 96 | # Code-block preferences 97 | csharp_prefer_braces = true:silent 98 | csharp_prefer_simple_using_statement = true:suggestion 99 | 100 | # Expression-level preferences 101 | csharp_prefer_simple_default_expression = true:suggestion 102 | csharp_style_deconstructed_variable_declaration = true:suggestion 103 | csharp_style_inlined_variable_declaration = true:suggestion 104 | csharp_style_pattern_local_over_anonymous_function = true:suggestion 105 | csharp_style_prefer_index_operator = true:suggestion 106 | csharp_style_prefer_range_operator = true:suggestion 107 | csharp_style_throw_expression = true:suggestion 108 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion 109 | csharp_style_unused_value_expression_statement_preference = discard_variable:silent 110 | 111 | # 'using' directive preferences 112 | csharp_using_directive_placement = outside_namespace:silent 113 | 114 | #### C# Formatting Rules #### 115 | 116 | # New line preferences 117 | csharp_new_line_before_catch = true 118 | csharp_new_line_before_else = true 119 | csharp_new_line_before_finally = true 120 | csharp_new_line_before_members_in_anonymous_types = true 121 | csharp_new_line_before_members_in_object_initializers = true 122 | csharp_new_line_before_open_brace = all 123 | csharp_new_line_between_query_expression_clauses = true 124 | 125 | # Indentation preferences 126 | csharp_indent_block_contents = true 127 | csharp_indent_braces = false 128 | csharp_indent_case_contents = true 129 | csharp_indent_case_contents_when_block = true 130 | csharp_indent_labels = no_change 131 | csharp_indent_switch_labels = true 132 | 133 | # Space preferences 134 | csharp_space_after_cast = false 135 | csharp_space_after_colon_in_inheritance_clause = true 136 | csharp_space_after_comma = true 137 | csharp_space_after_dot = false 138 | csharp_space_after_keywords_in_control_flow_statements = true 139 | csharp_space_after_semicolon_in_for_statement = true 140 | csharp_space_around_binary_operators = before_and_after 141 | csharp_space_around_declaration_statements = false 142 | csharp_space_before_colon_in_inheritance_clause = true 143 | csharp_space_before_comma = false 144 | csharp_space_before_dot = false 145 | csharp_space_before_open_square_brackets = false 146 | csharp_space_before_semicolon_in_for_statement = false 147 | csharp_space_between_empty_square_brackets = false 148 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 149 | csharp_space_between_method_call_name_and_opening_parenthesis = false 150 | csharp_space_between_method_call_parameter_list_parentheses = false 151 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 152 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 153 | csharp_space_between_method_declaration_parameter_list_parentheses = false 154 | csharp_space_between_parentheses = false 155 | csharp_space_between_square_brackets = false 156 | 157 | # Wrapping preferences 158 | csharp_preserve_single_line_blocks = true 159 | csharp_preserve_single_line_statements = true 160 | 161 | #### Naming styles #### 162 | 163 | # Naming rules 164 | 165 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 166 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 167 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 168 | 169 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 170 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 171 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 172 | 173 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 174 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 175 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 176 | 177 | # Symbol specifications 178 | 179 | dotnet_naming_symbols.interface.applicable_kinds = interface 180 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 181 | dotnet_naming_symbols.interface.required_modifiers = 182 | 183 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 184 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 185 | dotnet_naming_symbols.types.required_modifiers = 186 | 187 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 188 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 189 | dotnet_naming_symbols.non_field_members.required_modifiers = 190 | 191 | # Naming styles 192 | 193 | dotnet_naming_style.pascal_case.required_prefix = 194 | dotnet_naming_style.pascal_case.required_suffix = 195 | dotnet_naming_style.pascal_case.word_separator = 196 | dotnet_naming_style.pascal_case.capitalization = pascal_case 197 | 198 | dotnet_naming_style.begins_with_i.required_prefix = I 199 | dotnet_naming_style.begins_with_i.required_suffix = 200 | dotnet_naming_style.begins_with_i.word_separator = 201 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 202 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.suo 3 | bin/ 4 | obj/ 5 | packages/ 6 | .vs/ 7 | Dist/ -------------------------------------------------------------------------------- /CSProlog.Core.Test/CSProlog.Core.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /CSProlog.Core.Test/PrologEngine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | using Prolog; 4 | 5 | namespace CSProlog.Core.Test 6 | { 7 | public class PrologEngineTest 8 | { 9 | [Fact] 10 | public void ConsultFromString_GetOneSolution() 11 | { 12 | var prolog = new PrologEngine(persistentCommandHistory: false); 13 | 14 | // 'socrates' is human. 15 | prolog.ConsultFromString("human(socrates)."); 16 | // 'R2-D2' is droid. 17 | prolog.ConsultFromString("droid(r2d2)."); 18 | // human is bound to die. 19 | prolog.ConsultFromString("mortal(X) :- human(X)."); 20 | 21 | // Question: Shall 'socrates' die? 22 | var solution1 = prolog.GetFirstSolution(query: "mortal(socrates)."); 23 | Assert.True(solution1.Solved); // = "True" (Yes) 24 | 25 | // Question: Shall 'R2-D2' die? 26 | var solution2 = prolog.GetFirstSolution(query: "mortal(r2d2)."); 27 | Assert.False(solution2.Solved); // = "False" (No) 28 | } 29 | 30 | [Fact] 31 | public void ConsultFromString_GetAllSolutions_Adhoc() 32 | { 33 | var prolog = new PrologEngine(persistentCommandHistory: false); 34 | 35 | // 'socrates' is human. 36 | prolog.ConsultFromString("human(socrates)."); 37 | // 'R2-D2' is droid. 38 | prolog.ConsultFromString("droid(r2d2)."); 39 | // human is bound to die. 40 | prolog.ConsultFromString("mortal(X) :- human(X)."); 41 | 42 | prolog.GetFirstSolution(query: "listing."); 43 | 44 | SolutionSet solutionset1 = prolog.GetAllSolutions(null, "human(H)"); 45 | Console.WriteLine("====================================="); 46 | Console.WriteLine(solutionset1.ErrMsg); 47 | Console.WriteLine("====================================="); 48 | Assert.True(solutionset1.Success); 49 | if (solutionset1.Success) 50 | { 51 | var s = solutionset1[0]; 52 | foreach (Variable v in s.NextVariable) 53 | Console.WriteLine(string.Format("{0} ({1}) = {2}", v.Name, v.Type, v.Value)); 54 | 55 | } 56 | 57 | } 58 | 59 | [Fact] 60 | public void HelpTest() 61 | { 62 | var prolog = new PrologEngine(persistentCommandHistory: false); 63 | var s1 = prolog.GetFirstSolution("help."); 64 | Assert.True(s1.Solved); // = "True" (Yes) [help atleast ran] 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /CSProlog.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 16 3 | VisualStudioVersion = 16.0.29924.181 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{435BB1A6-EBA7-4F55-BF99-AF1C65FC43E2}" 6 | ProjectSection(SolutionItems) = preProject 7 | .editorconfig = .editorconfig 8 | appveyor.yml = appveyor.yml 9 | EndProjectSection 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PLd", "PLd\PLd.csproj", "{B7438FBF-6E46-4065-A60B-1B1CA2AC9875}" 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PLw", "PLw\PLw.csproj", "{BB06ADF9-92C3-4F92-8397-5ACC92208528}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PLx", "PLx\PLx.csproj", "{E84A59D2-E868-4108-BE9A-55CBB7E85E36}" 16 | EndProject 17 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSProlog", "CSProlog\CSProlog.csproj", "{6A947B78-96D1-45F2-BB9F-036586BAB544}" 18 | EndProject 19 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSProlog.Core.Test", "CSProlog.Core.Test\CSProlog.Core.Test.csproj", "{927B2CA6-BB69-422F-8107-B2E5EE9A6C4C}" 20 | EndProject 21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PL.NETcore", "PL.NETcore\PL.NETcore.csproj", "{191FF3C7-503C-4C3E-AC49-46B9BCB4B396}" 22 | EndProject 23 | Global 24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 25 | Debug|Any CPU = Debug|Any CPU 26 | LibraryRelease|Any CPU = LibraryRelease|Any CPU 27 | Release|Any CPU = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {B7438FBF-6E46-4065-A60B-1B1CA2AC9875}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {B7438FBF-6E46-4065-A60B-1B1CA2AC9875}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {B7438FBF-6E46-4065-A60B-1B1CA2AC9875}.LibraryRelease|Any CPU.ActiveCfg = Release|Any CPU 33 | {B7438FBF-6E46-4065-A60B-1B1CA2AC9875}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {B7438FBF-6E46-4065-A60B-1B1CA2AC9875}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {BB06ADF9-92C3-4F92-8397-5ACC92208528}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {BB06ADF9-92C3-4F92-8397-5ACC92208528}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {BB06ADF9-92C3-4F92-8397-5ACC92208528}.LibraryRelease|Any CPU.ActiveCfg = Release|Any CPU 38 | {BB06ADF9-92C3-4F92-8397-5ACC92208528}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {BB06ADF9-92C3-4F92-8397-5ACC92208528}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {E84A59D2-E868-4108-BE9A-55CBB7E85E36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {E84A59D2-E868-4108-BE9A-55CBB7E85E36}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {E84A59D2-E868-4108-BE9A-55CBB7E85E36}.LibraryRelease|Any CPU.ActiveCfg = Release|Any CPU 43 | {E84A59D2-E868-4108-BE9A-55CBB7E85E36}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {E84A59D2-E868-4108-BE9A-55CBB7E85E36}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {6A947B78-96D1-45F2-BB9F-036586BAB544}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {6A947B78-96D1-45F2-BB9F-036586BAB544}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {6A947B78-96D1-45F2-BB9F-036586BAB544}.LibraryRelease|Any CPU.ActiveCfg = Release|Any CPU 48 | {6A947B78-96D1-45F2-BB9F-036586BAB544}.LibraryRelease|Any CPU.Build.0 = Release|Any CPU 49 | {6A947B78-96D1-45F2-BB9F-036586BAB544}.Release|Any CPU.ActiveCfg = Release|Any CPU 50 | {6A947B78-96D1-45F2-BB9F-036586BAB544}.Release|Any CPU.Build.0 = Release|Any CPU 51 | {927B2CA6-BB69-422F-8107-B2E5EE9A6C4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 52 | {927B2CA6-BB69-422F-8107-B2E5EE9A6C4C}.Debug|Any CPU.Build.0 = Debug|Any CPU 53 | {927B2CA6-BB69-422F-8107-B2E5EE9A6C4C}.LibraryRelease|Any CPU.ActiveCfg = Release|Any CPU 54 | {927B2CA6-BB69-422F-8107-B2E5EE9A6C4C}.LibraryRelease|Any CPU.Build.0 = Release|Any CPU 55 | {927B2CA6-BB69-422F-8107-B2E5EE9A6C4C}.Release|Any CPU.ActiveCfg = Release|Any CPU 56 | {927B2CA6-BB69-422F-8107-B2E5EE9A6C4C}.Release|Any CPU.Build.0 = Release|Any CPU 57 | {191FF3C7-503C-4C3E-AC49-46B9BCB4B396}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 58 | {191FF3C7-503C-4C3E-AC49-46B9BCB4B396}.Debug|Any CPU.Build.0 = Debug|Any CPU 59 | {191FF3C7-503C-4C3E-AC49-46B9BCB4B396}.LibraryRelease|Any CPU.ActiveCfg = Release|Any CPU 60 | {191FF3C7-503C-4C3E-AC49-46B9BCB4B396}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {191FF3C7-503C-4C3E-AC49-46B9BCB4B396}.Release|Any CPU.Build.0 = Release|Any CPU 62 | EndGlobalSection 63 | GlobalSection(SolutionProperties) = preSolution 64 | HideSolutionNode = FALSE 65 | EndGlobalSection 66 | GlobalSection(ExtensibilityGlobals) = postSolution 67 | SolutionGuid = {D1917349-2AD7-41E1-B8E7-E1BE1AABA632} 68 | EndGlobalSection 69 | EndGlobal 70 | -------------------------------------------------------------------------------- /CSProlog/BaseTerm.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/CSProlog/BaseTerm.cs -------------------------------------------------------------------------------- /CSProlog/Builtins.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/CSProlog/Builtins.cs -------------------------------------------------------------------------------- /CSProlog/CSProlog.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard1.4;net35 5 | $(NoWarn);1591 6 | true 7 | CSProlog 8 | C#Prolog (CSProlog) 9 | $(AssemblyTitle) 10 | CSProlog 11 | 1.6.0 12 | $(PackageTargetFallback);dnxcore50 13 | CSProlog 14 | 6.0.0.0 15 | John Pool,Amersfoort,Netherlands,J.Sakamoto,Josh Ahlstrom 16 | N/A 17 | C#Prolog -- A Prolog interpreter written in C#. 18 | Can easily be integrated in C# programs. 19 | Characteristics: reliable and fairly fast interpreter, command line interface, builtin DCG, XML- and JSON-predicates, SQL-predicates, extendible. 20 | Copyright (C) 2007-2015 John Pool -- j.pool@ision.nl 21 | https://github.com/jsakamoto/CSharpProlog/blob/vnext/master/LICENSE 22 | https://github.com/jsakamoto/CSharpProlog/ 23 | Prolog interpreter 24 | v.6.0.0 25 | - BREAKING CHANGE: Remove "SAMPLES, TESTING & EXPERIMENTAL" predefined predicates. (including CHAT-80 support) 26 | - Fix: "help" predefined predicate dose not work. 27 | - Enhance: GetAllSolutions can work with null file name. 28 | v.5.0.0.1 29 | - Support: .NET Standard 1.4 (.NET Core) and UWP 30 | v.5.0.0 31 | - BREAKING CHANGE: Remove dependency of "System.Windows.Forms". 32 | - NuGet package release 33 | true 34 | 35 | 36 | 37 | TRACE;NETSTANDARD;RELEASE;NETSTANDARD1_4;RELEASE;NETSTANDARD1_4 38 | 39 | 40 | TRACE;DEBUG;NETSTANDARD 41 | 42 | 43 | TRACE;RELEASE;mswindows;net35 44 | 45 | 46 | TRACE;DEBUG;mswindows;net35 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /CSProlog/CSProlog.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /CSProlog/CrossRefTable.cs: -------------------------------------------------------------------------------- 1 | namespace Prolog 2 | { 3 | using System; 4 | using System.Text; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | 9 | /* _______________________________________________________________________________________________ 10 | | | 11 | | C#Prolog -- Copyright (C) 2007-2014 John Pool -- j.pool@ision.nl | 12 | | | 13 | | This library is free software; you can redistribute it and/or modify it under the terms of | 14 | | the GNU General Public License as published by the Free Software Foundation; either version | 15 | | 2 of the License, or any later version. | 16 | | | 17 | | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | 18 | | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 19 | | See the GNU General Public License for details, or enter 'license.' at the command prompt. | 20 | |_______________________________________________________________________________________________| 21 | */ 22 | 23 | // PrologParser Generator version 4.0 -- Date/Time: 22-12-2010 8:42:54 24 | 25 | public partial class PrologEngine 26 | { 27 | // CrossRefTable implements a cross reference table for the predicates making up the 'program'. 28 | // Each predicate corresponds to a row. The entries in the row are the predicates that are called. 29 | // CalculateClosure () calculates the indirect calls (i.e. if A calls B and B calls C directly, 30 | // then the closure would calculate the indirect call A -> C. 31 | // Direct calls have an entry value 'false', indirect calls an entry value 'true'. 32 | #region CrossRefTable 33 | public class CrossRefTable : Dictionary 34 | { 35 | List axis; // predicate names sorted alphabetically 36 | int dimension { get { return axis.Count; } } 37 | bool findAllCalls; // i.e. both direct and indirect (result of closure) 38 | bool? result; 39 | public bool FindAllCalls { get { return findAllCalls; } set { findAllCalls = value; } } 40 | 41 | public CrossRefTable() 42 | { 43 | axis = new List(); 44 | findAllCalls = false; 45 | } 46 | 47 | 48 | public void Reset() 49 | { 50 | Clear(); 51 | axis.Clear(); 52 | findAllCalls = false; 53 | } 54 | 55 | 56 | public void AddPredicate(PredicateDescr pd) 57 | { 58 | // add predicate only if not already present 59 | int i = axis.BinarySearch(pd); 60 | 61 | if (i < 0) axis.Insert(~i, pd); // keep range sorted 62 | } 63 | 64 | 65 | #region indices 66 | // used only when registering the direct calls, not for the closure (indirect calls) 67 | public bool? this[PredicateDescr row, PredicateDescr col] 68 | { 69 | set 70 | { 71 | this[CompoundKey(row, col)] = false; // i.e. a direct call 72 | } 73 | 74 | get 75 | { 76 | if (TryGetValue(CompoundKey(row, col), out result)) return result; 77 | 78 | return null; 79 | } 80 | } 81 | 82 | // used only when calculating the indirect calls (CalculateClosure) 83 | public bool? this[int i, int j] 84 | { 85 | set 86 | { 87 | string key = CompoundKey(axis[i], axis[j]); 88 | bool? result; 89 | 90 | // do not overwrite 'false', as this would hide the fact that a direct call exists 91 | if (!TryGetValue(key, out result)) 92 | this[key] = true; 93 | } 94 | 95 | get 96 | { 97 | if (TryGetValue(CompoundKey(axis[i], axis[j]), out result)) return result; 98 | 99 | return null; 100 | } 101 | } 102 | #endregion indices 103 | 104 | // find all predicates called by 'row' 105 | public IEnumerable Row(PredicateDescr row) 106 | { 107 | foreach (PredicateDescr col in axis) 108 | if ((result = this[row, col]) != null) 109 | if (findAllCalls || result == false) 110 | yield return col; 111 | } 112 | 113 | // find all predicates that call 'col' 114 | public IEnumerable Col(PredicateDescr col) 115 | { 116 | foreach (PredicateDescr row in axis) 117 | if ((result = this[row, col]) != null) 118 | if (findAllCalls || result == false) 119 | yield return col; 120 | } 121 | 122 | 123 | // Warshall algorithm -- Journal of the ACM, Jan. 1962, pp. 11-12 124 | // This algorithm calculates the indirect calls. 125 | public void CalculateClosure() 126 | { 127 | int i, j, k; 128 | 129 | for (i = 0; i < dimension; i++) 130 | for (j = 0; j < dimension; j++) 131 | if (this[j, i] != null) 132 | for (k = 0; k < dimension; k++) 133 | if (this[i, k] != null) 134 | this[j, k] = true; // 'true' to indicate entry is indirect call (result of closure) 135 | } 136 | 137 | 138 | public void GenerateCsvFile(string fileName) 139 | { 140 | bool? value; 141 | StreamWriter sr = null; 142 | int rowTotal; 143 | int[] colTotal = new int[axis.Count]; 144 | 145 | try 146 | { 147 | sr = new StreamWriter(File.OpenWrite(fileName)); 148 | 149 | sr.WriteLine(Enquote("Call table. Row calls column entries. 'D' stands for direct call, 'I' for indirect call")); 150 | sr.WriteLine(); 151 | 152 | // column titles 153 | for (int j = 0; j < dimension; j++) 154 | { 155 | sr.Write(";{0}", Enquote(axis[j].Name)); 156 | colTotal[j] = 0; 157 | } 158 | 159 | sr.WriteLine(";TOTAL"); 160 | 161 | // rows 162 | for (int i = 0; i < dimension; i++) 163 | { 164 | sr.Write(Enquote(axis[i].Name)); // row title 165 | rowTotal = 0; 166 | 167 | for (int j = 0; j < dimension; j++) 168 | { 169 | sr.Write(';'); 170 | 171 | if ((value = this[i, j]) != null) 172 | { 173 | sr.Write((value == false) ? "D" : "I"); 174 | rowTotal++; 175 | colTotal[j]++; 176 | } 177 | } 178 | 179 | sr.WriteLine(";{0}", rowTotal); 180 | } 181 | 182 | // column totals 183 | sr.Write("TOTAL"); 184 | 185 | for (int j = 0; j < dimension; j++) sr.Write(";{0}", colTotal[j]); 186 | 187 | sr.WriteLine(); 188 | } 189 | catch (Exception e) 190 | { 191 | IO.Error("Error while trying to save Excel spreadsheet '{0}'. Message was:\r\n{1}" + e.Message); 192 | } 193 | finally 194 | { 195 | if (sr != null) sr.Dispose(); 196 | } 197 | } 198 | 199 | string Enquote(string s) 200 | { 201 | return '"' + s.Replace("\"", "\"\"") + '"'; 202 | } 203 | 204 | string CompoundKey(PredicateDescr row, PredicateDescr col) 205 | { 206 | return string.Format("{0} {1}", row.Name, col.Name); 207 | } 208 | } 209 | #endregion CrossRefTable 210 | 211 | #region PredicateDescr CompareTo () 212 | public partial class PredicateDescr : IComparable 213 | { 214 | public int CompareTo(PredicateDescr pd) 215 | { 216 | int result = Functor.CompareTo(pd.Functor); 217 | 218 | if (result == 0) return Arity.CompareTo(pd.Arity); 219 | 220 | return result; 221 | } 222 | } 223 | #endregion 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /CSProlog/ExternalUsage.cs: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------------------- 2 | 3 | C#Prolog -- Copyright (C) 2007-2015 John Pool -- j.pool@ision.nl 4 | 5 | This library is free software; you can redistribute it and/or modify it under the terms of 6 | the GNU Lesser General Public License as published by the Free Software Foundation; either 7 | version 3.0 of the License, or any later version. 8 | 9 | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | See the GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl-3.0.html), or 12 | enter 'license' at the command prompt. 13 | 14 | -------------------------------------------------------------------------------------------*/ 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | using System.IO; 19 | using System.Text; 20 | using System.Xml; 21 | #if mswindows 22 | using System.Windows.Forms; 23 | #endif 24 | 25 | namespace Prolog 26 | { 27 | #region SolutionSet 28 | public class SolutionSet 29 | { 30 | string query; 31 | public string Query { get { return query; } internal set { query = value; } } 32 | bool success; 33 | public bool Success { get { return success; } internal set { success = value; } } 34 | string errorMsg; 35 | public string ErrMsg { get { return errorMsg; } internal set { errorMsg = value; } } 36 | public bool HasError { get { return errorMsg != null; } } 37 | List solutionSet; 38 | public int Count { get { return solutionSet.Count; } } 39 | Solution currVarSet; 40 | 41 | public SolutionSet() 42 | { 43 | solutionSet = new List(); 44 | success = false; 45 | errorMsg = null; 46 | } 47 | 48 | internal void CreateVarSet() 49 | { 50 | solutionSet.Add(currVarSet = new Solution()); 51 | } 52 | 53 | internal void AddToVarSet(string name, string type, string value) 54 | { 55 | currVarSet.Add(name, type, value); 56 | success = true; 57 | } 58 | 59 | public IEnumerable NextSolution 60 | { 61 | get 62 | { 63 | foreach (Solution s in solutionSet) 64 | yield return s; 65 | } 66 | } 67 | 68 | public Solution this[int i] 69 | { 70 | get 71 | { 72 | return solutionSet[i]; 73 | } 74 | } 75 | 76 | public override string ToString() 77 | { 78 | if (errorMsg != null) 79 | return errorMsg; 80 | 81 | if (success) 82 | { 83 | if (solutionSet.Count == 0) 84 | return "yes"; 85 | else 86 | { 87 | StringBuilder sb = new StringBuilder(); 88 | int i = 0; 89 | foreach (Solution s in solutionSet) 90 | sb.AppendLine("Solution {0}\r\n{1}", ++i, s.ToString()); 91 | 92 | return sb.ToString(); 93 | } 94 | } 95 | else 96 | return "no"; 97 | } 98 | } 99 | #endregion SolutionSet 100 | 101 | #region Solution 102 | public class Solution // a solution is a set of variables 103 | { 104 | List variables; 105 | int Count { get { return variables.Count; } } 106 | 107 | public Solution() 108 | { 109 | variables = new List(); 110 | } 111 | 112 | internal void Add(string name, string type, string value) 113 | { 114 | variables.Add(new Variable(name, type, value)); 115 | } 116 | 117 | public IEnumerable NextVariable 118 | { 119 | get 120 | { 121 | foreach (Variable v in variables) 122 | yield return v; 123 | } 124 | } 125 | 126 | public Variable this[int i] 127 | { 128 | get 129 | { 130 | return variables[i]; 131 | } 132 | } 133 | 134 | public override string ToString() 135 | { 136 | StringBuilder sb = new StringBuilder(); 137 | 138 | foreach (Variable v in variables) 139 | sb.AppendLine(v.ToString()); 140 | 141 | return sb.ToString(); 142 | } 143 | } 144 | #endregion Solution 145 | 146 | #region Variable 147 | public class Variable 148 | { 149 | string name; 150 | public string Name { get { return name; } } 151 | string type; 152 | public string Type { get { return type; } } 153 | string value; 154 | public string Value { get { return value; } } 155 | 156 | public Variable(string name, string type, string value) 157 | { 158 | this.name = name; 159 | this.type = type; 160 | this.value = value; 161 | } 162 | 163 | public override string ToString() 164 | { 165 | return string.Format("{0} ({1}) = {2}", name, type, value); 166 | } 167 | } 168 | #endregion Variable 169 | 170 | public partial class PrologEngine 171 | { 172 | #if mswindows 173 | #region Batch Processing 174 | public bool ProcessArgs(string[] args, bool windowsMode) 175 | { 176 | if (args.Length == 0) return false; 177 | 178 | // Process command line arguments. First is a query, optional second 179 | // arg is number of backtrack attempts (default is 0, 'infinite' = *) 180 | // If the first argument contains spaces, it must be enclosed in double quotes. 181 | // Example: pld "['path.pl'], solve( p(2,2), L)" 4 182 | string command = args[0].Dequoted().Trim(); 183 | Query = command + (command.EndsWith(".") ? null : "."); // append a dot if necessary 184 | int solutionCount = 0; // i.e. find all solutions (backtrack until failure; value corresponds to '*') 185 | string msg = null; 186 | 187 | if (args.Length > 2) 188 | msg = string.Format("Superfluous argument '{0}'", args[2]); 189 | else if (args.Length == 2 && !(int.TryParse(args[1], out solutionCount) || args[1] == "*")) 190 | msg = string.Format("Illegal value '{0}' for maximum number of solutions", args[1]); 191 | else 192 | solutionCount = 1; 193 | 194 | if (msg == null) 195 | { 196 | int i = 0; 197 | bool found = false; // true if at least one solution found 198 | 199 | foreach (PrologEngine.ISolution s in SolutionIterator) 200 | { 201 | if (Error || (!found && !s.Solved)) // only an immediate 'no' give rise to an error 202 | { 203 | msg = s.ToString(); 204 | 205 | break; 206 | } 207 | 208 | if (++i == solutionCount) break; 209 | 210 | found = true; 211 | } 212 | } 213 | 214 | if (msg != null) 215 | { 216 | if (windowsMode) 217 | MessageBox.Show(msg); 218 | else 219 | Console.WriteLine(msg); 220 | 221 | Environment.ExitCode = 1; // sets DOS ERRORLEVEL to 1 222 | } 223 | 224 | return true; 225 | } 226 | #endregion Batch Processing 227 | #endif 228 | 229 | #region GetAllSolutionsXml 230 | // Store solutions in an xml structure 231 | #if !NETSTANDARD 232 | public string GetAllSolutionsXml(string sourceFileName, string destinFileName, string query) 233 | { 234 | return GetAllSolutionsXml(sourceFileName, destinFileName, query, 0); 235 | } 236 | 237 | public string GetAllSolutionsXml(string sourceFileName, string destinFileName, string query, int maxSolutionCount) 238 | { 239 | XmlTextWriter xtw = null; 240 | StreamWriter sw = null; 241 | 242 | if (destinFileName == null) 243 | xtw = new XmlTextWriter(new MemoryStream(), System.Text.Encoding.GetEncoding(1252)); 244 | else 245 | xtw = new XmlTextWriter(destinFileName, null); 246 | 247 | xtw.Formatting = Formatting.Indented; 248 | xtw.WriteStartDocument(); 249 | 250 | try 251 | { 252 | if (sourceFileName != null) 253 | Reset(); 254 | 255 | if (sourceFileName != null) 256 | Consult(sourceFileName); 257 | 258 | Query = query + (query.EndsWith(".") ? null : "."); // append a dot if necessary 259 | int i = 0; 260 | bool found = false; // true if at least one solution found 261 | bool firstSol = true; 262 | 263 | foreach (PrologEngine.ISolution s in SolutionIterator) 264 | { 265 | if (Error) 266 | { 267 | xtw.WriteStartElement("error"); 268 | xtw.WriteCData(s.ToString()); 269 | xtw.WriteEndElement(); 270 | 271 | break; 272 | } 273 | else if (!found && !s.Solved) 274 | { 275 | xtw.WriteStartElement("solutions"); 276 | xtw.WriteAttributeString("success", "false"); 277 | xtw.WriteStartElement("query"); 278 | xtw.WriteString(query); 279 | xtw.WriteEndElement(); 280 | 281 | break; 282 | } 283 | 284 | if (firstSol) 285 | { 286 | firstSol = false; 287 | xtw.WriteStartElement("solutions"); 288 | xtw.WriteAttributeString("success", "true"); 289 | xtw.WriteStartElement("query"); 290 | xtw.WriteString(query); 291 | xtw.WriteEndElement(); 292 | } 293 | 294 | bool firstVar = true; 295 | 296 | foreach (PrologEngine.IVarValue varValue in s.VarValuesIterator) 297 | { 298 | if (varValue.DataType == "none") break; 299 | 300 | if (firstVar) 301 | { 302 | firstVar = false; 303 | xtw.WriteStartElement("solution"); 304 | } 305 | 306 | xtw.WriteStartElement("variable"); 307 | xtw.WriteAttributeString("name", varValue.Name); 308 | xtw.WriteAttributeString("type", varValue.DataType); 309 | xtw.WriteString(varValue.Value.ToString()); 310 | xtw.WriteEndElement(); // variable 311 | } 312 | 313 | if (!firstVar) xtw.WriteEndElement(); // solution 314 | 315 | if (++i == maxSolutionCount) break; 316 | 317 | found = true; 318 | } 319 | 320 | if (!Error) xtw.WriteEndElement(); // solutions 321 | 322 | xtw.WriteEndDocument(); 323 | xtw.Flush(); 324 | 325 | if (destinFileName == null) 326 | { 327 | if (xtw.BaseStream == null) return null; 328 | 329 | return new ASCIIEncoding().GetString(((MemoryStream)xtw.BaseStream).ToArray()); 330 | } 331 | else 332 | return null; 333 | } 334 | finally 335 | { 336 | if (xtw != null) xtw.Close(); 337 | if (sw != null) sw.Close(); 338 | } 339 | } 340 | #endif 341 | #endregion GetAllSolutionsXml 342 | 343 | 344 | #region GetAllSolutions 345 | // Store solutions in an GetAllSolutions class 346 | public SolutionSet GetAllSolutions(string sourceFileName, string query) 347 | { 348 | return GetAllSolutions(sourceFileName, query, 0); 349 | } 350 | 351 | public SolutionSet GetAllSolutions(string sourceFileName, string query, int maxSolutionCount) 352 | { 353 | 354 | SolutionSet solutions = new SolutionSet(); 355 | 356 | try 357 | { 358 | if (sourceFileName != null) Reset(); 359 | 360 | if (sourceFileName != null) Consult(sourceFileName); 361 | 362 | Query = solutions.Query = query + (query.EndsWith(".") ? null : "."); // append a dot if necessary 363 | int i = 0; 364 | bool found = false; 365 | bool varFound = false; 366 | 367 | foreach (PrologEngine.ISolution s in SolutionIterator) 368 | { 369 | if (Error) 370 | { 371 | solutions.ErrMsg = s.ToString(); 372 | 373 | break; 374 | } 375 | else if (!found && !s.Solved) 376 | break; 377 | 378 | solutions.Success = true; 379 | bool firstVar = true; 380 | 381 | foreach (PrologEngine.IVarValue varValue in s.VarValuesIterator) 382 | { 383 | if (varValue.DataType == "none") break; 384 | 385 | if (firstVar) 386 | { 387 | firstVar = false; 388 | solutions.CreateVarSet(); 389 | } 390 | 391 | solutions.AddToVarSet(varValue.Name, varValue.DataType, varValue.Value.ToString()); 392 | varFound = true; 393 | } 394 | 395 | if (++i == maxSolutionCount || !varFound) break; 396 | 397 | found = true; 398 | } 399 | } 400 | catch (Exception e) 401 | { 402 | solutions.ErrMsg = e.Message; 403 | } 404 | 405 | return solutions; 406 | } 407 | #endregion GetAllSolutions 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /CSProlog/IO.cs: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------------------- 2 | 3 | C#Prolog -- Copyright (C) 2007-2015 John Pool -- j.pool@ision.nl 4 | 5 | This library is free software; you can redistribute it and/or modify it under the terms of 6 | the GNU Lesser General Public License as published by the Free Software Foundation; either 7 | version 3.0 of the License, or any later version. 8 | 9 | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | See the GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl-3.0.html), or 12 | enter 'license' at the command prompt. 13 | 14 | -------------------------------------------------------------------------------------------*/ 15 | 16 | using System; 17 | using System.IO; 18 | using System.Text; 19 | 20 | namespace Prolog 21 | { 22 | #if NETSTANDARD 23 | using ApplicationException = System.Exception; 24 | #endif 25 | 26 | #region BasicIo 27 | public abstract class BasicIo 28 | { 29 | #region abstract methods 30 | public abstract string ReadLine(); 31 | 32 | public abstract int ReadChar(); 33 | 34 | public abstract void Write(string s); 35 | 36 | public abstract void WriteLine(string s); 37 | 38 | public abstract void WriteLine(); 39 | 40 | public abstract void Clear(); 41 | 42 | public abstract void Reset(); 43 | #endregion abstract methods 44 | 45 | public void Write(string s, params object[] o) 46 | { 47 | Write(string.Format(s, o)); 48 | } 49 | 50 | public void WriteLine(string s, params object[] o) 51 | { 52 | WriteLine(string.Format(s, o)); 53 | } 54 | } 55 | #endregion BasicIo 56 | 57 | #region DosIO. Base class for DOS IO 58 | public class DosIO : BasicIo 59 | { 60 | public override string ReadLine() 61 | { 62 | return Console.ReadLine(); 63 | } 64 | 65 | 66 | public override int ReadChar() 67 | { 68 | return Console.ReadKey().KeyChar; 69 | } 70 | 71 | 72 | public override void Write(string s) 73 | { 74 | Console.Write(s); 75 | } 76 | 77 | 78 | public override void WriteLine(string s) 79 | { 80 | Console.WriteLine(s); 81 | } 82 | 83 | 84 | public override void WriteLine() 85 | { 86 | Console.WriteLine(); 87 | } 88 | 89 | 90 | public override void Clear() 91 | { 92 | Console.Clear(); 93 | } 94 | 95 | 96 | public override void Reset() 97 | { 98 | } 99 | } 100 | #endregion DosIO 101 | 102 | #region FileIO. Base class for text File IO 103 | public class FileIO : BasicIo 104 | { 105 | StreamReader inFile; 106 | StreamWriter outFile; 107 | 108 | public FileIO(string inFileName, string outFileName) 109 | { 110 | // no try/catch, as I would not know how to handle the exception caught 111 | inFile = new StreamReader(File.OpenRead(inFileName)); 112 | outFile = new StreamWriter(File.OpenWrite(outFileName)); 113 | outFile.AutoFlush = true; // file will contain all output even if not closed explicitly 114 | } 115 | 116 | public override string ReadLine() 117 | { 118 | if (inFile == null) 119 | throw new ApplicationException("FileIO class: input file is not defined"); 120 | 121 | return inFile.ReadLine(); 122 | } 123 | 124 | 125 | public override int ReadChar() 126 | { 127 | if (inFile == null) 128 | throw new ApplicationException("FileIO class: input file is not defined"); 129 | 130 | return inFile.Read(); 131 | } 132 | 133 | 134 | public override void Write(string s) 135 | { 136 | if (outFile == null) 137 | throw new ApplicationException("FileIO class: output file is not defined"); 138 | 139 | outFile.Write(s); 140 | } 141 | 142 | 143 | public override void WriteLine(string s) 144 | { 145 | if (outFile == null) 146 | throw new ApplicationException("FileIO class: output file is not defined"); 147 | 148 | outFile.WriteLine(s); 149 | } 150 | 151 | 152 | public override void WriteLine() 153 | { 154 | if (outFile == null) 155 | throw new ApplicationException("FileIO class: output file is not defined"); 156 | 157 | outFile.WriteLine(); 158 | } 159 | 160 | 161 | public override void Clear() 162 | { 163 | } 164 | 165 | 166 | public override void Reset() 167 | { 168 | } 169 | 170 | 171 | public void Close() 172 | { 173 | if (inFile != null) inFile.Dispose(); 174 | 175 | if (outFile != null) outFile.Dispose(); 176 | } 177 | } 178 | #endregion FileIO 179 | 180 | public partial class PrologEngine 181 | { 182 | FileReaderTerm currentFileReader; 183 | FileWriterTerm currentFileWriter; 184 | public BasicIo BasicIO { set { IO.BasicIO = value; } } 185 | 186 | #region BaseRead(Line/Term/Char)CurrentInput and BaseWriteCurrentOutput 187 | // BaseReadCurrentInput. Input is read from StandardInput. 188 | // StandardInput is the file set by the see command, or Console if no such file exists. 189 | string BaseReadLineCurrentInput() // returns null at end of file 190 | { 191 | return (currentFileReader == null) ? IO.ReadLine() : currentFileReader.ReadLine(); 192 | } 193 | 194 | 195 | BaseTerm BaseReadTermCurrentInput() 196 | { 197 | if (currentFileReader == null) 198 | { 199 | StringBuilder query = new StringBuilder(); 200 | string line; 201 | PrologParser p = new PrologParser(this); 202 | 203 | bool first = true; 204 | 205 | while (true) 206 | { 207 | IO.Write("|: "); 208 | 209 | if (first) first = false; else query.AppendLine(); 210 | 211 | if ((line = IO.ReadLine()) == null) return FileTerm.END_OF_FILE; 212 | 213 | query.Append(line = line.Trim()); 214 | 215 | if (line.EndsWith(".")) break; 216 | } 217 | 218 | p.StreamIn = "&reading\r\n" + query.ToString(); // equal to parser ReadingSym 219 | BaseTerm result = p.ReadTerm; 220 | 221 | return (result == null) ? FileTerm.END_OF_FILE : result; 222 | } 223 | 224 | return currentFileReader.ReadTerm(); 225 | } 226 | 227 | 228 | int BaseReadCharCurrentInput() // returns -1 at end of file 229 | { 230 | return (currentFileReader == null) ? IO.ReadChar() : currentFileReader.ReadChar(); 231 | } 232 | 233 | 234 | // BaseWriteCurrentOutput 235 | // Output from print, display, tab, put etc. is written to StandardOutput. 236 | // StandardOutput is the file set by the tell command, or Console if 237 | // no such file exists. 238 | void BaseWriteCurrentOutput(string s) 239 | { 240 | if (currentFileWriter == null) 241 | IO.Write(s); 242 | else 243 | currentFileWriter.Write(s); 244 | } 245 | 246 | 247 | void BaseWriteCurrentOutput(string s, object[] args) 248 | { 249 | BaseWriteCurrentOutput(string.Format(s, args)); 250 | } 251 | #endregion BaseRead(Line/Term/Char)CurrentInput and BaseWriteCurrentOutput 252 | 253 | 254 | #region Read(Line/Char) and Write(Line) 255 | BaseTerm ReadTerm() 256 | { 257 | return BaseReadTermCurrentInput(); 258 | } 259 | 260 | 261 | string ReadLine() 262 | { 263 | return BaseReadLineCurrentInput(); 264 | } 265 | 266 | 267 | int ReadChar() 268 | { 269 | return BaseReadCharCurrentInput(); 270 | } 271 | 272 | 273 | void Write(BaseTerm t, bool dequote) 274 | { 275 | if (t.IsString) 276 | BaseWriteCurrentOutput(dequote ? t.FunctorToString : '"' + t.FunctorToString + '"'); 277 | else if (t.IsAtom) 278 | BaseWriteCurrentOutput(dequote ? t.FunctorToString.Dequoted("'") : t.FunctorToString); 279 | else 280 | BaseWriteCurrentOutput(t.ToString()); 281 | } 282 | 283 | 284 | public void Write(string s) 285 | { 286 | BaseWriteCurrentOutput(s); 287 | } 288 | 289 | 290 | public void Write(string s, params object[] args) 291 | { 292 | BaseWriteCurrentOutput(s, args); 293 | } 294 | 295 | 296 | public void WriteLine(string s) 297 | { 298 | BaseWriteCurrentOutput(s + Environment.NewLine); 299 | } 300 | 301 | 302 | public void WriteLine(string s, params object[] args) 303 | { 304 | BaseWriteCurrentOutput(s + Environment.NewLine, args); 305 | } 306 | 307 | 308 | public void NewLine() 309 | { 310 | BaseWriteCurrentOutput(Environment.NewLine); 311 | } 312 | #endregion Read(Line/Char) and Write(Line) 313 | 314 | 315 | // for IO *not* generated by Prolog predicates and not subject to 316 | // current input and current output (i.e. error messages etc.) 317 | public static class IO 318 | { 319 | static BasicIo basicIO; 320 | public static BasicIo BasicIO { get { return basicIO; } set { basicIO = value; } } 321 | public static bool Verbose = true; // message display 322 | static int debugLevel = 0; 323 | 324 | public static void SetDebugLevel(int level) 325 | { 326 | debugLevel = level; 327 | } 328 | 329 | public static bool Error(string msg, params object[] o) 330 | { 331 | Error(String.Format(msg, o)); 332 | 333 | return false; 334 | } 335 | 336 | public static bool Error(string msg) 337 | { 338 | if (Globals.LineNo == -1) // interactive 339 | throw new ParserException("\r\n*** error: " + msg); 340 | else 341 | throw new ParserException(String.Format("\r\n*** error in line {0} at position {1}: {2}", 342 | Globals.LineNo, Globals.ColNo, msg)); 343 | } 344 | 345 | 346 | public static void Warning(string msg, params object[] o) 347 | { 348 | BasicIO.WriteLine(string.Format("\r\n*** warning: " + msg, o)); 349 | } 350 | 351 | 352 | public static void Warning(string msg) 353 | { 354 | BasicIO.WriteLine("\r\n*** warning: " + msg); 355 | } 356 | 357 | 358 | public static void Message(string msg, params object[] o) 359 | { 360 | BasicIO.WriteLine(string.Format("\r\n--- " + msg, o)); 361 | } 362 | 363 | 364 | public static void Message(string msg) 365 | { 366 | BasicIO.WriteLine("\r\n--- " + msg); 367 | } 368 | 369 | 370 | public static void Fatal(string msg, params object[] o) 371 | { 372 | throw new Exception("\r\n*** fatal: " + String.Format(msg, o)); 373 | } 374 | 375 | 376 | public static void Fatal(string msg) 377 | { 378 | throw new Exception("\r\n*** fatal: " + msg); 379 | } 380 | 381 | 382 | public static string ReadLine() 383 | { 384 | return BasicIO.ReadLine(); 385 | } 386 | 387 | 388 | public static int ReadChar() 389 | { 390 | return BasicIO.ReadChar(); 391 | } 392 | 393 | 394 | public static void Write(string s, params object[] o) 395 | { 396 | BasicIO.Write(string.Format(s, o)); 397 | } 398 | 399 | 400 | public static void Write(string s) 401 | { 402 | BasicIO.Write(s); 403 | } 404 | 405 | 406 | public static void WriteLine(string s, params object[] o) 407 | { 408 | BasicIO.WriteLine(string.Format(s, o)); 409 | } 410 | 411 | 412 | public static void WriteLine(string s) 413 | { 414 | BasicIO.WriteLine(s); 415 | } 416 | 417 | 418 | public static void WriteLine() 419 | { 420 | BasicIO.WriteLine(); 421 | } 422 | 423 | 424 | public static void ClearScreen() 425 | { 426 | BasicIO.Clear(); 427 | } 428 | } 429 | } 430 | } 431 | -------------------------------------------------------------------------------- /CSProlog/Internet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Mail; 4 | using System.Security.Cryptography.X509Certificates; 5 | 6 | namespace Prolog 7 | { 8 | public partial class PrologEngine 9 | { 10 | #region engine-mail 11 | static bool SendMail(string smtpHost, int port, string toAddr, string subject, string body) 12 | { 13 | try 14 | { 15 | SmtpClient client = new SmtpClient(smtpHost, port); 16 | MailAddress from = new MailAddress("xxxxxx@xxxxxx.xx"); 17 | MailAddress to = new MailAddress(toAddr); 18 | MailMessage msg = new MailMessage(); 19 | msg.From = from; 20 | msg.To.Add(to); 21 | msg.Subject = subject; 22 | msg.Body = body; 23 | //client.EnableSsl = true; 24 | //ServicePointManager.CertificatePolicy = new AcceptAllCertificatePolicy (); 25 | client.Send(msg); 26 | //client.SendAsync (msg, userState); 27 | 28 | //Attachment attachment = new Attachment ("you attachment file"); 29 | //msg.Attachments.Add (attachment); 30 | 31 | return true; 32 | } 33 | catch (Exception x) 34 | { 35 | IO.Warning("Unable to send message. Reason was:\r\n{0}", x.Message); 36 | 37 | return false; 38 | } 39 | } 40 | 41 | 42 | class AcceptAllCertificatePolicy : ICertificatePolicy 43 | { 44 | public AcceptAllCertificatePolicy() 45 | { 46 | } 47 | 48 | public bool CheckValidationResult(ServicePoint sPoint, 49 | X509Certificate cert, WebRequest wRequest, int certProb) 50 | { 51 | // Always accept 52 | return true; 53 | } 54 | } 55 | #endregion engine-mail 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /CSProlog/Miscellaneous.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/CSProlog/Miscellaneous.cs -------------------------------------------------------------------------------- /CSProlog/PG/JSON.cs: -------------------------------------------------------------------------------- 1 | //#define LL1_tracing 2 | namespace Prolog 3 | { 4 | using System; 5 | using System.IO; 6 | using System.Text; 7 | using System.Xml; 8 | using System.Collections; 9 | using System.Collections.Generic; 10 | using System.Collections.Specialized; 11 | using System.Globalization; 12 | using System.Threading; 13 | using System.Diagnostics; 14 | 15 | /* _______________________________________________________________________________________________ 16 | | | 17 | | C#Prolog -- Copyright (C) 2007 John Pool -- j.pool@ision.nl | 18 | | | 19 | | This library is free software; you can redistribute it and/or modify it under the terms of | 20 | | the GNU General Public License as published by the Free Software Foundation; either version | 21 | | 2 of the License, or any later version. | 22 | | | 23 | | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | 24 | | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 25 | | See the GNU General Public License for details, or enter 'license.' at the command prompt. | 26 | |_______________________________________________________________________________________________| 27 | */ 28 | 29 | // Parser Generator version 4.0 -- Date/Time: 10-Feb-14 08:40:11 30 | 31 | 32 | public partial class PrologEngine 33 | { 34 | #region JsonParser 35 | public partial class JsonParser : BaseParser 36 | { 37 | public static readonly string VersionTimeStamp = "2014-02-10 08:40:11"; 38 | 39 | 40 | #region Terminal definition 41 | 42 | /* The following constants are defined in BaseParser.cs: 43 | const int Undefined = 0; 44 | const int Comma = 1; 45 | const int LeftParen = 2; 46 | const int RightParen = 3; 47 | const int Identifier = 4; 48 | const int IntLiteral = 5; 49 | const int ppDefine = 6; 50 | const int ppUndefine = 7; 51 | const int ppIf = 8; 52 | const int ppIfNot = 9; 53 | const int ppElse = 10; 54 | const int ppElseIf = 11; 55 | const int ppEndIf = 12; 56 | const int RealLiteral = 13; 57 | const int ImagLiteral = 14; 58 | const int StringLiteral = 15; 59 | const int CharLiteral = 16; 60 | const int CommentStart = 17; 61 | const int CommentSingle = 18; 62 | const int EndOfLine = 19; 63 | const int ANYSYM = 20; 64 | const int EndOfInput = 21; 65 | */ 66 | const int LSqBracket = 22; 67 | const int RSqBracket = 23; 68 | const int LCuBracket = 24; 69 | const int RCuBracket = 25; 70 | const int Colon = 26; 71 | const int TrueSym = 27; 72 | const int FalseSym = 28; 73 | const int NullSym = 29; 74 | // Total number of terminals: 75 | public const int terminalCount = 30; 76 | 77 | public static void FillTerminalTable(BaseTrie terminalTable) 78 | { 79 | terminalTable.Add(Undefined, SymbolClass.None, "Undefined"); 80 | terminalTable.Add(Comma, SymbolClass.None, "Comma", ","); 81 | terminalTable.Add(LeftParen, SymbolClass.Group, "LeftParen", "("); 82 | terminalTable.Add(RightParen, SymbolClass.Group, "RightParen", ")"); 83 | terminalTable.Add(Identifier, SymbolClass.Id, "Identifier"); 84 | terminalTable.Add(IntLiteral, SymbolClass.Number, "IntLiteral"); 85 | terminalTable.Add(ppDefine, SymbolClass.Meta, "ppDefine", "#define"); 86 | terminalTable.Add(ppUndefine, SymbolClass.Meta, "ppUndefine", "#undefine"); 87 | terminalTable.Add(ppIf, SymbolClass.Meta, "ppIf", "#if"); 88 | terminalTable.Add(ppIfNot, SymbolClass.Meta, "ppIfNot", "#ifnot"); 89 | terminalTable.Add(ppElse, SymbolClass.Meta, "ppElse", "#else"); 90 | terminalTable.Add(ppElseIf, SymbolClass.Meta, "ppElseIf", "#elseif"); 91 | terminalTable.Add(ppEndIf, SymbolClass.Meta, "ppEndIf", "#endif"); 92 | terminalTable.Add(RealLiteral, SymbolClass.Number, "RealLiteral"); 93 | terminalTable.Add(ImagLiteral, SymbolClass.Number, "ImagLiteral"); 94 | terminalTable.Add(StringLiteral, SymbolClass.Text, "StringLiteral"); 95 | terminalTable.Add(CharLiteral, SymbolClass.Text, "CharLiteral"); 96 | terminalTable.Add(CommentStart, SymbolClass.Comment, "CommentStart", "/*"); 97 | terminalTable.Add(CommentSingle, SymbolClass.Comment, "CommentSingle", "%"); 98 | terminalTable.Add(EndOfLine, SymbolClass.None, "EndOfLine"); 99 | terminalTable.Add(ANYSYM, SymbolClass.None, "ANYSYM"); 100 | terminalTable.Add(EndOfInput, SymbolClass.None, "EndOfInput"); 101 | terminalTable.Add(LSqBracket, SymbolClass.None, "LSqBracket", "["); 102 | terminalTable.Add(RSqBracket, SymbolClass.None, "RSqBracket", "]"); 103 | terminalTable.Add(LCuBracket, SymbolClass.None, "LCuBracket", "{"); 104 | terminalTable.Add(RCuBracket, SymbolClass.None, "RCuBracket", "}"); 105 | terminalTable.Add(Colon, SymbolClass.None, "Colon", ":"); 106 | terminalTable.Add(TrueSym, SymbolClass.None, "TrueSym", "true"); 107 | terminalTable.Add(FalseSym, SymbolClass.None, "FalseSym", "false"); 108 | terminalTable.Add(NullSym, SymbolClass.None, "NullSym", "null"); 109 | } 110 | 111 | #endregion Terminal definition 112 | 113 | #region Constructor 114 | public JsonParser() 115 | { 116 | terminalTable = new BaseTrie(terminalCount, false); 117 | FillTerminalTable(terminalTable); 118 | symbol = new Symbol(this); 119 | streamInPrefix = ""; 120 | streamInPreLen = 0; 121 | } 122 | #endregion constructor 123 | 124 | #region NextSymbol, GetSymbol 125 | protected override bool GetSymbol(TerminalSet followers, bool done, bool genXCPN) 126 | { 127 | string s; 128 | 129 | if (symbol.IsProcessed) NextSymbol(); 130 | 131 | symbol.SetProcessed(done); 132 | if (parseAnyText || followers.IsEmpty()) return true; 133 | 134 | if (syntaxErrorStat) return false; 135 | 136 | if (symbol.TerminalId == ANYSYM || followers.Contains(symbol.TerminalId)) return true; 137 | 138 | switch (symbol.TerminalId) 139 | { 140 | case EndOfLine: 141 | if (seeEndOfLine) s = ""; else goto default; 142 | s = ""; 143 | break; 144 | case EndOfInput: 145 | s = ""; 146 | break; 147 | default: 148 | s = String.Format("\"{0}\"", symbol.ToString()); 149 | break; 150 | } 151 | 152 | s = String.Format("*** Unexpected symbol: {0}{1}*** Expected one of: {2}", s, 153 | Environment.NewLine, terminalTable.TerminalImageSet(followers)); 154 | if (genXCPN) 155 | SyntaxError = s; 156 | else 157 | errorMessage = s; 158 | 159 | return true; 160 | } 161 | #endregion NextSymbol, GetSymbol 162 | 163 | #region PARSER PROCEDURES 164 | public override void RootCall() 165 | { 166 | JsonStruct(new TerminalSet(terminalCount, EndOfInput)); 167 | } 168 | 169 | 170 | public override void Delegates() 171 | { 172 | 173 | } 174 | 175 | 176 | #region JsonStruct 177 | private void JsonStruct(TerminalSet _TS) 178 | { 179 | GetSymbol(new TerminalSet(terminalCount, LSqBracket, LCuBracket), false, true); 180 | if (symbol.TerminalId == LCuBracket) 181 | { 182 | JsonObject(_TS, out jsonListTerm); 183 | } 184 | else 185 | { 186 | JsonArray(_TS, out jsonListTerm); 187 | } 188 | } 189 | #endregion 190 | 191 | #region JsonObject 192 | private void JsonObject(TerminalSet _TS, out BaseTerm t) 193 | { 194 | BaseTerm e; 195 | List listItems = new List(); 196 | GetSymbol(new TerminalSet(terminalCount, LCuBracket), true, true); 197 | GetSymbol(new TerminalSet(terminalCount, StringLiteral, RCuBracket), false, true); 198 | if (symbol.TerminalId == StringLiteral) 199 | { 200 | while (true) 201 | { 202 | JsonPair(new TerminalSet(terminalCount, Comma, RCuBracket), out e); 203 | listItems.Add(e); 204 | GetSymbol(new TerminalSet(terminalCount, Comma, RCuBracket), false, true); 205 | if (symbol.TerminalId == Comma) 206 | { 207 | symbol.SetProcessed(); 208 | } 209 | else 210 | break; 211 | } 212 | } 213 | GetSymbol(new TerminalSet(terminalCount, RCuBracket), true, true); 214 | t = JsonTerm.FromArray(listItems.ToArray()); 215 | } 216 | #endregion 217 | 218 | #region JsonPair 219 | private void JsonPair(TerminalSet _TS, out BaseTerm t) 220 | { 221 | BaseTerm t0, t1; 222 | GetSymbol(new TerminalSet(terminalCount, StringLiteral), true, true); 223 | t0 = new StringTerm(symbol.ToString().Dequoted()); 224 | GetSymbol(new TerminalSet(terminalCount, Colon), true, true); 225 | JsonValue(_TS, out t1); 226 | t = new OperatorTerm(opTable, PrologParser.COLON, t0, t1); 227 | } 228 | #endregion 229 | 230 | #region JsonArray 231 | private void JsonArray(TerminalSet _TS, out BaseTerm t) 232 | { 233 | BaseTerm e; 234 | List listItems = new List(); 235 | GetSymbol(new TerminalSet(terminalCount, LSqBracket), true, true); 236 | GetSymbol(new TerminalSet(terminalCount, IntLiteral, RealLiteral, StringLiteral, LSqBracket, RSqBracket, LCuBracket, 237 | TrueSym, FalseSym, NullSym), false, true); 238 | if (symbol.IsMemberOf(IntLiteral, RealLiteral, StringLiteral, LSqBracket, LCuBracket, TrueSym, FalseSym, NullSym)) 239 | { 240 | while (true) 241 | { 242 | JsonValue(new TerminalSet(terminalCount, Comma, RSqBracket), out e); 243 | listItems.Add(e); 244 | GetSymbol(new TerminalSet(terminalCount, Comma, RSqBracket), false, true); 245 | if (symbol.TerminalId == Comma) 246 | { 247 | symbol.SetProcessed(); 248 | } 249 | else 250 | break; 251 | } 252 | } 253 | GetSymbol(new TerminalSet(terminalCount, RSqBracket), true, true); 254 | t = new CompoundTerm("array", ListTerm.ListFromArray(listItems.ToArray(), BaseTerm.EMPTYLIST)); 255 | } 256 | #endregion 257 | 258 | #region JsonValue 259 | private void JsonValue(TerminalSet _TS, out BaseTerm t) 260 | { 261 | GetSymbol(new TerminalSet(terminalCount, IntLiteral, RealLiteral, StringLiteral, LSqBracket, LCuBracket, TrueSym, 262 | FalseSym, NullSym), false, true); 263 | if (symbol.TerminalId == LCuBracket) 264 | { 265 | JsonObject(_TS, out t); 266 | } 267 | else if (symbol.TerminalId == LSqBracket) 268 | { 269 | JsonArray(_TS, out t); 270 | } 271 | else 272 | { 273 | JsonLiteral(_TS, out t); 274 | } 275 | } 276 | #endregion 277 | 278 | #region JsonLiteral 279 | private void JsonLiteral(TerminalSet _TS, out BaseTerm t) 280 | { 281 | GetSymbol(new TerminalSet(terminalCount, IntLiteral, RealLiteral, StringLiteral, TrueSym, FalseSym, NullSym), false, 282 | true); 283 | if (symbol.IsMemberOf(IntLiteral, RealLiteral)) 284 | { 285 | GetSymbol(new TerminalSet(terminalCount, IntLiteral, RealLiteral), false, true); 286 | if (symbol.TerminalId == IntLiteral) 287 | { 288 | symbol.SetProcessed(); 289 | } 290 | else 291 | { 292 | symbol.SetProcessed(); 293 | } 294 | t = new DecimalTerm(symbol.ToDecimal()); 295 | } 296 | else if (symbol.TerminalId == StringLiteral) 297 | { 298 | symbol.SetProcessed(); 299 | t = new StringTerm(symbol.ToString().Dequoted()); 300 | } 301 | else if (symbol.TerminalId == TrueSym) 302 | { 303 | symbol.SetProcessed(); 304 | t = new AtomTerm("true"); 305 | } 306 | else if (symbol.TerminalId == FalseSym) 307 | { 308 | symbol.SetProcessed(); 309 | t = new AtomTerm("false"); 310 | } 311 | else 312 | { 313 | symbol.SetProcessed(); 314 | t = new AtomTerm("null"); 315 | } 316 | } 317 | #endregion 318 | 319 | 320 | #endregion PARSER PROCEDURES 321 | } 322 | #endregion JsonParser 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /CSProlog/PG/JSON.grm: -------------------------------------------------------------------------------- 1 | /* 2 | Grammar for JSON data, following http://www.json.org/ 3 | and compliant with http://www.ietf.org/rfc/rfc4627 4 | 5 | "Start Symbol" = 6 | "Case Sensitive" = True 7 | "Character Mapping" = 'Unicode' 8 | 9 | ! ------------------------------------------------- Sets 10 | 11 | {Unescaped} = {All Valid} - {&1 .. &19} - ["\] 12 | {Hex} = {Digit} + [ABCDEFabcdef] 13 | {Digit9} = {Digit} - [0] 14 | 15 | ! ------------------------------------------------- Terminals 16 | 17 | Number = '-'?('0'|{Digit9}{Digit}*)('.'{Digit}+)?([Ee][+-]?{Digit}+)? 18 | String = '"'({Unescaped}|'\'(["\/bfnrt]|'u'{Hex}{Hex}{Hex}{Hex}))*'"' 19 | 20 | ! ------------------------------------------------- Rules 21 | 22 | ::= 23 | | 24 | 25 | ::= '{' '}' 26 | | '{' '}' 27 | 28 | ::= 29 | | ',' 30 | 31 | ::= String ':' 32 | 33 | ::= '[' ']' 34 | | '[' ']' 35 | 36 | ::= 37 | | ',' 38 | 39 | ::= String 40 | | Number 41 | | 42 | | 43 | | true 44 | | false 45 | | null 46 | 47 | */ 48 | 49 | SETTINGS 50 | 51 | NameSpace = 'Prolog' 52 | ParserClassPrefix = 'Json' 53 | TerminalDescrPayload = 'object' 54 | CrNoticeNr = 2 55 | CaseSensitive = Y 56 | CodeStringChar = '|' 57 | CommentStart = '/*' 58 | CommentEnd = '*/' 59 | SingleComment = '%' 60 | StringStart = '"' 61 | StringEnd = '"' 62 | StringEscape = '\' 63 | EOICheck = Y 64 | 65 | 66 | TERMINALS 67 | 68 | LSqBracket = '[' 69 | RSqBracket = ']' 70 | LCuBracket = '{' 71 | RCuBracket = '}' 72 | Colon = ':' 73 | TrueSym = 'true' 74 | FalseSym = 'false' 75 | NullSym = 'null' 76 | 77 | 78 | RULES 79 | 80 | JsonStruct -> 81 | (: JsonObject + |out jsonListTerm| 82 | [] JsonArray + |out jsonListTerm| 83 | :) 84 | --- 85 | 86 | 87 | JsonObject + |out BaseTerm t| -> 88 | |BaseTerm e;| 89 | |List listItems = new List ();| 90 | LCuBracket 91 | (: JsonPair + |out e| 92 | |listItems.Add (e);| 93 | :) CHAIN Comma OPTION 94 | RCuBracket 95 | |t = JsonTerm.FromArray (listItems.ToArray ());| 96 | --- 97 | 98 | 99 | JsonPair + |out BaseTerm t| -> 100 | |BaseTerm t0, t1;| 101 | StringLiteral 102 | |t0 = new StringTerm (symbol.ToString ().Dequoted ());| 103 | Colon 104 | JsonValue + |out t1| 105 | |t = new OperatorTerm (opTable, PrologParser.COLON, t0, t1);| 106 | --- 107 | 108 | 109 | JsonArray + |out BaseTerm t| -> 110 | |BaseTerm e;| 111 | |List listItems = new List ();| 112 | LSqBracket 113 | (: JsonValue + |out e| 114 | |listItems.Add (e);| 115 | :) CHAIN Comma OPTION 116 | RSqBracket 117 | |t = new CompoundTerm ("array", ListTerm.ListFromArray (listItems.ToArray (), BaseTerm.EMPTYLIST));| 118 | --- 119 | 120 | 121 | JsonValue + |out BaseTerm t| -> 122 | (: JsonObject + |out t| 123 | [] JsonArray + |out t| 124 | [] JsonLiteral + |out t| 125 | :) 126 | --- 127 | 128 | 129 | JsonLiteral + |out BaseTerm t| -> 130 | (: (: IntLiteral [] RealLiteral :) 131 | |t = new DecimalTerm (symbol.ToDecimal ());| 132 | [] StringLiteral 133 | |t = new StringTerm (symbol.ToString ().Dequoted ());| 134 | %? [] Identifier % for hex numbers starting with a letter only 135 | %? |t = new AtomTerm (symbol.ToString ().Dequoted ());| 136 | [] TrueSym 137 | |t = new AtomTerm ("true");| 138 | [] FalseSym 139 | |t = new AtomTerm ("false");| 140 | [] NullSym 141 | |t = new AtomTerm ("null");| 142 | :) 143 | --- 144 | 145 | 146 | ROOT 147 | 148 | JsonStruct 149 | -------------------------------------------------------------------------------- /CSProlog/PG/JsonParser.cs: -------------------------------------------------------------------------------- 1 | //#define showToken 2 | 3 | namespace Prolog 4 | { 5 | using System; 6 | using System.IO; 7 | using System.Text; 8 | using System.Xml; 9 | using System.Collections; 10 | using System.Globalization; 11 | using System.Diagnostics; 12 | 13 | /* _______________________________________________________________________________________________ 14 | | | 15 | | C#Prolog -- Copyright (C) 2007-2014 John Pool -- j.pool@ision.nl | 16 | | | 17 | | This library is free software; you can redistribute it and/or modify it under the terms of | 18 | | the GNU General Public License as published by the Free Software Foundation; either version | 19 | | 2 of the License, or any later version. | 20 | | | 21 | | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | 22 | | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 23 | | See the GNU General Public License for details, or enter 'license.' at the command prompt. | 24 | |_______________________________________________________________________________________________| 25 | */ 26 | 27 | public partial class PrologEngine 28 | { 29 | #region JsonParser 30 | public partial class JsonParser : BaseParser 31 | { 32 | BaseTerm jsonListTerm; 33 | public BaseTerm JsonListTerm { get { return jsonListTerm; } } 34 | OperatorTable opTable; 35 | public OperatorTable OpTable { set { opTable = value; } } 36 | 37 | #region ScanNumber 38 | protected override void ScanNumber() // overridden: also scans hex numbers 39 | { 40 | bool isReal; 41 | bool hexFound = false; 42 | StreamPointer savPosition; 43 | bool ok = true; 44 | 45 | do 46 | { 47 | NextCh(); 48 | 49 | if (!(ok = Char.IsDigit(ch))) 50 | { 51 | if (ok = ch.IsHexChar()) hexFound = true; 52 | } 53 | } 54 | while (ok); 55 | 56 | symbol.TerminalId = IntLiteral; 57 | isReal = true; // assumed until proven conversily 58 | 59 | if (!hexFound) 60 | { 61 | if (ch == '.') // fractional part? 62 | { 63 | // save dot position 64 | savPosition = streamInPtr; 65 | NextCh(); 66 | 67 | if (Char.IsDigit(ch)) 68 | { 69 | symbol.TerminalId = RealLiteral; 70 | 71 | do { NextCh(); } while (Char.IsDigit(ch)); 72 | } 73 | else // not a digit after period 74 | { 75 | InitCh(savPosition); // 'unread' dot 76 | isReal = false; // ... and remember this 77 | } 78 | } 79 | 80 | if (isReal) // integer or real, possibly with scale factor 81 | { 82 | savPosition = streamInPtr; 83 | 84 | if (ch == 'e' || ch == 'E') 85 | { // scale factor 86 | NextCh(); 87 | 88 | if (ch == '+' || ch == '-') NextCh(); 89 | 90 | if (Char.IsDigit(ch)) 91 | { 92 | do 93 | { 94 | NextCh(); 95 | } 96 | while (Char.IsDigit(ch)); 97 | 98 | symbol.TerminalId = RealLiteral; 99 | } 100 | else if (!stringMode) // Error in real syntax 101 | InitCh(savPosition); 102 | } 103 | } 104 | } 105 | 106 | symbol.Final = streamInPtr.Position; 107 | } 108 | 109 | 110 | protected override bool ScanFraction() 111 | { 112 | StreamPointer savPosition = streamInPtr; // Position of '.' 113 | 114 | do NextCh(); while (Char.IsDigit(ch)); 115 | 116 | bool result = (streamInPtr.Position > savPosition.Position + 1); // a fraction 117 | 118 | if (result) 119 | { 120 | if (ch == 'i') 121 | { 122 | symbol.TerminalId = ImagLiteral; 123 | NextCh(); 124 | } 125 | else 126 | symbol.TerminalId = RealLiteral; 127 | } 128 | else 129 | InitCh(savPosition); 130 | 131 | return result; 132 | } 133 | #endregion ScanNumber 134 | 135 | #region ScanIdOrTerminal 136 | protected override void ScanIdOrTerminalOrCommentStart() 137 | { 138 | TerminalDescr tRec; 139 | bool firstLow = Char.IsLower(ch); 140 | StreamPointer iPtr = streamInPtr; 141 | StreamPointer tPtr = iPtr; 142 | int aLen = (ch.IsIdStartChar()) ? 1 : 0; // length of longest Identifier sofar 143 | int tLen = 0; // length of longest Terminal sofar 144 | int fCnt = 0; // count of calls to FindCharAndSubtree 145 | bool isDot = (ch == '.'); // remains valid only if symbol length is 1 146 | terminalTable.FindCharInSubtreeReset(); 147 | 148 | while (fCnt++ >= 0 && terminalTable.FindCharInSubtree(ch, out tRec)) 149 | { 150 | if (tRec != null) 151 | { 152 | symbol.TerminalId = tRec.IVal; 153 | symbol.Payload = tRec.Payload; // not used 154 | symbol.Class = tRec.Class; 155 | tLen = fCnt; 156 | tPtr = streamInPtr; // next char to be processed 157 | 158 | if (symbol.TerminalId == CommentStart || symbol.TerminalId == CommentSingle) return; 159 | 160 | if (terminalTable.AtLeaf) break; // terminal cannot be extended 161 | } 162 | 163 | NextCh(); 164 | 165 | if (aLen == fCnt && (Char.IsLetterOrDigit(ch) || ch == '_')) 166 | { 167 | aLen++; 168 | iPtr = streamInPtr; 169 | } 170 | } // fCnt++ by last (i.e. failing) Call 171 | 172 | /* 173 | At this point: (in the Prolog case, read 'Identifier and Atom made up 174 | from specials' for 'Identifier'): 175 | - tLen has length of BaseTrie terminal (if any, 0 otherwise); 176 | - aLen has length of Identifier (if any, 0 otherwise); 177 | - fCnt is the number of characters inspected (for Id AND terminal) 178 | - The character pointer is on the last character inspected (for both) 179 | Iff aLen = fCnt then the entire sequence read sofar is an Identifier. 180 | Now try extending the Identifier, only meaningful if iLen = fCnt. 181 | Do not do this for an Atom made up from specials if a Terminal was recognized !! 182 | */ 183 | 184 | if (aLen == fCnt) 185 | { 186 | while (true) 187 | { 188 | NextCh(); 189 | 190 | if (Char.IsLetterOrDigit(ch) || ch == '_') 191 | { 192 | aLen++; 193 | iPtr = streamInPtr; 194 | } 195 | else 196 | break; 197 | } 198 | } 199 | 200 | if (aLen > tLen) // tLen = 0 iff Terminal == Undefined 201 | { 202 | symbol.TerminalId = Identifier; 203 | symbol.Class = SymbolClass.Id; 204 | InitCh(iPtr); 205 | } 206 | else if (symbol.TerminalId == Undefined) 207 | InitCh(iPtr); 208 | else // we have a terminal != Identifier 209 | { 210 | if (aLen == tLen) symbol.Class = SymbolClass.Id; 211 | InitCh(tPtr); 212 | } 213 | 214 | NextCh(); 215 | } 216 | #endregion 217 | 218 | #region NextSymbol 219 | protected override void NextSymbol(string _Proc) 220 | { 221 | if (symbol.AbsSeqNo != 0 && streamInPtr.FOnLine) streamInPtr.FOnLine = false; 222 | 223 | symbol.PrevFinal = symbol.Final; 224 | 225 | if (symbol.TerminalId == EndOfInput) 226 | SyntaxError = "*** Trying to read beyond end of input"; 227 | 228 | prevTerminal = symbol.TerminalId; 229 | symbol.Class = SymbolClass.None; 230 | symbol.Payload = null; 231 | bool Break = false; 232 | 233 | do 234 | { 235 | while (Char.IsWhiteSpace(ch)) NextCh(); 236 | 237 | symbol.Start = streamInPtr.Position; 238 | symbol.LineNo = streamInPtr.LineNo; 239 | symbol.LineStart = streamInPtr.LineStart; 240 | symbol.TerminalId = Undefined; 241 | 242 | if (endText) 243 | symbol.TerminalId = EndOfInput; 244 | else if (streamInPtr.EndLine) 245 | symbol.TerminalId = EndOfLine; 246 | else if (Char.IsDigit(ch)) 247 | ScanNumber(); 248 | else if (ch == DQUOTE) 249 | ScanString(); 250 | else 251 | ScanIdOrTerminalOrCommentStart(); 252 | 253 | symbol.Final = streamInPtr.Position; 254 | 255 | if (symbol.TerminalId == EndOfLine) 256 | { 257 | eoLineCount++; 258 | NextCh(); 259 | Break = seeEndOfLine; 260 | } 261 | else 262 | { 263 | eoLineCount = 0; 264 | 265 | switch (symbol.TerminalId) 266 | { 267 | case Identifier: 268 | Break = true; 269 | break; 270 | case EndOfInput: 271 | Break = true; 272 | break; 273 | case CommentStart: 274 | if (stringMode) 275 | Break = true; 276 | 277 | if (!DoComment("*/", true, streamInPtr.FOnLine)) 278 | ErrorMessage = "Unterminated comment starting at line " + symbol.LineNo.ToString(); 279 | 280 | break; 281 | case CommentSingle: 282 | if (stringMode) Break = true; else Break = false; 283 | DoComment("\n", false, streamInPtr.FOnLine); 284 | eoLineCount = 1; 285 | 286 | if (seeEndOfLine) 287 | { 288 | symbol.TerminalId = EndOfLine; 289 | Break = true; 290 | } 291 | 292 | break; 293 | default: 294 | if (seeEndOfLine && symbol.TerminalId != EndOfLine) streamInPtr.FOnLine = false; 295 | 296 | Break = true; 297 | break; 298 | } 299 | } 300 | } while (!Break); 301 | 302 | symbol.AbsSeqNo++; 303 | symbol.RelSeqNo++; 304 | #if showToken // a Console.Clear () will wipe out this output! 305 | IO.WriteLine ("NextSymbol[{0}] line {1}: '{2}' [{3}]", 306 | symbol.AbsSeqNo, symbol.LineNo, symbol.ToString (), symbol.ToName ()); 307 | #endif 308 | } 309 | #endregion NextSymbol 310 | } 311 | #endregion JsonParser 312 | } 313 | 314 | #region Extensions class 315 | static class JsonParserExtensions 316 | { 317 | public static bool IsHexChar(this char c) 318 | { 319 | return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); 320 | } 321 | } 322 | #endregion Extensions class 323 | } 324 | 325 | -------------------------------------------------------------------------------- /CSProlog/PG/JsonParserEx.cs: -------------------------------------------------------------------------------- 1 | //#define showToken 2 | 3 | namespace Prolog 4 | { 5 | using System; 6 | using System.IO; 7 | using System.Text; 8 | using System.Xml; 9 | using System.Collections; 10 | using System.Globalization; 11 | using System.Security.Principal; 12 | using System.Diagnostics; 13 | 14 | /* _______________________________________________________________________________________________ 15 | | | 16 | | C#Prolog -- Copyright (C) 2007 John Pool -- j.pool@ision.nl | 17 | | | 18 | | This library is free software; you can redistribute it and/or modify it under the terms of | 19 | | the GNU General Public License as published by the Free Software Foundation; either version | 20 | | 2 of the License, or any later version. | 21 | | | 22 | | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | 23 | | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 24 | | See the GNU General Public License for details, or enter 'license.' at the command prompt. | 25 | |_______________________________________________________________________________________________| 26 | */ 27 | 28 | public partial class PrologEngine 29 | { 30 | #region JsonParser 31 | public partial class JsonParser : BaseParser 32 | { 33 | BaseTerm jsonListTerm; 34 | public BaseTerm JsonListTerm { get { return jsonListTerm; } } 35 | OperatorTable opTable; 36 | public OperatorTable OpTable { set { opTable = value; } } 37 | 38 | #region ScanNumber 39 | protected override void ScanNumber () // overridden: also scans hex numbers 40 | { 41 | bool isReal; 42 | bool hexFound = false; 43 | StreamPointer savPosition; 44 | bool ok = true; 45 | 46 | do 47 | { 48 | NextCh (); 49 | 50 | if (!(ok = Char.IsDigit (ch))) 51 | { 52 | if (ok = ch.IsHexChar ()) hexFound = true; 53 | } 54 | } 55 | while (ok); 56 | 57 | symbol.Terminal = IntLiteral; 58 | isReal = true; // assumed until proven conversily 59 | 60 | if (!hexFound) 61 | { 62 | if (ch == '.') // fractional part? 63 | { 64 | // save dot position 65 | savPosition = streamInPtr; 66 | NextCh (); 67 | 68 | if (Char.IsDigit (ch)) 69 | { 70 | symbol.Terminal = RealLiteral; 71 | 72 | do { NextCh (); } while (Char.IsDigit (ch)); 73 | } 74 | else // not a digit after period 75 | { 76 | InitCh (savPosition); // 'unread' dot 77 | isReal = false; // ... and remember this 78 | } 79 | } 80 | 81 | if (isReal) // integer or real, possibly with scale factor 82 | { 83 | savPosition = streamInPtr; 84 | 85 | if (ch == 'e' || ch == 'E') 86 | { // scale factor 87 | NextCh (); 88 | 89 | if (ch == '+' || ch == '-') NextCh (); 90 | 91 | if (Char.IsDigit (ch)) 92 | { 93 | do 94 | { 95 | NextCh (); 96 | } 97 | while (Char.IsDigit (ch)); 98 | 99 | symbol.Terminal = RealLiteral; 100 | } 101 | else if (!stringMode) // Error in real syntax 102 | InitCh (savPosition); 103 | } 104 | } 105 | } 106 | 107 | symbol.Final = streamInPtr.Position; 108 | } 109 | 110 | 111 | protected override bool ScanFraction () 112 | { 113 | StreamPointer savPosition = streamInPtr; // Position of '.' 114 | 115 | do NextCh (); while (Char.IsDigit (ch)); 116 | 117 | bool result = (streamInPtr.Position > savPosition.Position + 1); // a fraction 118 | 119 | if (result) 120 | { 121 | if (ch == 'i') 122 | { 123 | symbol.Terminal = ImagLiteral; 124 | NextCh (); 125 | } 126 | else 127 | symbol.Terminal = RealLiteral; 128 | } 129 | else 130 | InitCh (savPosition); 131 | 132 | return result; 133 | } 134 | #endregion ScanNumber 135 | 136 | #region ScanIdOrTerminal 137 | protected override void ScanIdOrTerminal () 138 | { 139 | TerminalDescr tRec; 140 | bool firstLow = Char.IsLower (ch); 141 | StreamPointer iPtr = streamInPtr; 142 | StreamPointer tPtr = iPtr; 143 | int aLen = (ch.IsIdStartChar ()) ? 1 : 0; // length of longest Identifier sofar 144 | int tLen = 0; // length of longest Terminal sofar 145 | int fCnt = 0; // count of calls to FindCharAndSubtree 146 | bool isDot = (ch == '.'); // remains valid only if symbol length is 1 147 | terminalTable.FindCharInSubtreeReset (); 148 | 149 | while (fCnt++ >= 0 && terminalTable.FindCharInSubtree (ch, out tRec)) 150 | { 151 | if (tRec != null) 152 | { 153 | symbol.Terminal = tRec.IVal; 154 | symbol.Payload = tRec.Payload; // not used 155 | symbol.Type = tRec.Type; 156 | tLen = fCnt; 157 | tPtr = streamInPtr; // next char to be processed 158 | 159 | if (symbol.Terminal == CommentStart || symbol.Terminal == CommentSingle) return; 160 | 161 | if (terminalTable.AtLeaf) break; // terminal cannot be extended 162 | } 163 | 164 | NextCh (); 165 | 166 | if (aLen == fCnt && (Char.IsLetterOrDigit (ch) || ch == '_')) 167 | { 168 | aLen++; 169 | iPtr = streamInPtr; 170 | } 171 | } // fCnt++ by last (i.e. failing) Call 172 | 173 | /* 174 | At this point: (in the Prolog case, read 'Identifier and Atom made up 175 | from specials' for 'Identifier'): 176 | - tLen has length of BaseTrie terminal (if any, 0 otherwise); 177 | - aLen has length of Identifier (if any, 0 otherwise); 178 | - fCnt is the number of characters inspected (for Id AND terminal) 179 | - The character pointer is on the last character inspected (for both) 180 | Iff aLen = fCnt then the entire sequence read sofar is an Identifier. 181 | Now try extending the Identifier, only meaningful if iLen = fCnt. 182 | Do not do this for an Atom made up from specials if a Terminal was recognized !! 183 | */ 184 | 185 | if (aLen == fCnt) 186 | { 187 | while (true) 188 | { 189 | NextCh (); 190 | 191 | if (Char.IsLetterOrDigit (ch) || ch == '_') 192 | { 193 | aLen++; 194 | iPtr = streamInPtr; 195 | } 196 | else 197 | break; 198 | } 199 | } 200 | 201 | if (aLen > tLen) // tLen = 0 iff Terminal == Undefined 202 | { 203 | symbol.Terminal = Identifier; 204 | symbol.HasIdFormat = true; 205 | InitCh (iPtr); 206 | } 207 | else if (symbol.Terminal == Undefined) 208 | InitCh (iPtr); 209 | else // we have a terminal != Identifier 210 | { 211 | symbol.HasIdFormat = (aLen == tLen); 212 | InitCh (tPtr); 213 | } 214 | 215 | NextCh (); 216 | } 217 | #endregion 218 | 219 | #region NextSymbol 220 | protected override void NextSymbol (string _Proc) 221 | { 222 | if (symbol.AbsSeqNo != 0 && streamInPtr.FOnLine) streamInPtr.FOnLine = false; 223 | 224 | symbol.PrevFinal = symbol.Final; 225 | 226 | if (symbol.Terminal == EndOfInput) 227 | SyntaxError = "*** Trying to read beyond end of input"; 228 | 229 | prevTerminal = symbol.Terminal; 230 | symbol.HasIdFormat = false; 231 | symbol.Payload = null; 232 | bool Break = false; 233 | 234 | do 235 | { 236 | while (Char.IsWhiteSpace (ch)) NextCh (); 237 | 238 | symbol.Start = streamInPtr.Position; 239 | symbol.LineNo = streamInPtr.LineNo; 240 | symbol.LineStart = streamInPtr.LineStart; 241 | symbol.Terminal = Undefined; 242 | 243 | if (endText) 244 | symbol.Terminal = EndOfInput; 245 | else if (streamInPtr.EndLine) 246 | symbol.Terminal = EndOfLine; 247 | else if (Char.IsDigit (ch)) 248 | ScanNumber (); 249 | else if (ch == DQUOTE) 250 | ScanString (); 251 | else 252 | ScanIdOrTerminal (); 253 | 254 | symbol.Final = streamInPtr.Position; 255 | 256 | if (symbol.Terminal == EndOfLine) 257 | { 258 | eoLineCount++; 259 | NextCh (); 260 | Break = seeEndOfLine; 261 | } 262 | else 263 | { 264 | eoLineCount = 0; 265 | 266 | switch (symbol.Terminal) 267 | { 268 | case ppDefine: 269 | CheckPpIllegalSymbol (); 270 | ppDefineSymbol = true; 271 | break; 272 | case ppUndefine: 273 | CheckPpIllegalSymbol (); 274 | ppUndefineSymbol = true; 275 | break; 276 | case ppIf: 277 | case ppIfDef: 278 | CheckPpIllegalSymbol (); 279 | ppDoIfSymbol = true; 280 | ppElseOK.Push (true); // block is open 281 | break; 282 | case ppIfNot: 283 | case ppIfNDef: 284 | CheckPpIllegalSymbol (); 285 | ppDoIfNotSymbol = true; 286 | ppElseOK.Push (true); // block is open 287 | break; 288 | case ppElse: 289 | CheckPpIllegalSymbol (); 290 | 291 | if (!(bool)ppElseOK.Pop ()) Error ("Unexpected #else"); 292 | 293 | ppElseOK.Push (false); // no else allowed after an else 294 | ppXeqStack.Pop (); // remove the current value of ppProcessSource (pushed by the if-branch) 295 | 296 | // if the if-branch was executed, then this branch should not 297 | if (ppProcessSource) // ... it was executed 298 | ppProcessSource = !ppProcessSource; 299 | else // ... it was not. But execute this branch only if the outer scope value of ppProcessSource is true 300 | if ((bool)ppXeqStack.Peek ()) ppProcessSource = true; 301 | 302 | ppXeqStack.Push (ppProcessSource); // push the new value for this scope 303 | break; 304 | case ppEndIf: 305 | if (ppElseOK.Count == 0) Error ("Unexpected #endif"); 306 | ppElseOK.Pop (); // go to outer scope 307 | ppXeqStack.Pop (); 308 | ppProcessSource = (bool)ppXeqStack.Peek (); 309 | break; 310 | case Identifier: 311 | if (ppProcessSource && ppDefineSymbol) 312 | { 313 | ppSymbols [symbol.ToString ().ToLower ()] = true; // any non-null value will do 314 | ppDefineSymbol = false; 315 | } 316 | else if (ppProcessSource && ppUndefineSymbol) 317 | { 318 | ppSymbols.Remove (symbol.ToString ().ToLower ()); 319 | ppUndefineSymbol = false; 320 | } 321 | else if (ppDoIfSymbol) // identifier following #if 322 | { 323 | // do not alter ppProcessSource here if the outer scope value of ppProcessSource is false 324 | if (ppProcessSource && (bool)ppXeqStack.Peek ()) // ... value is true 325 | if (ppSymbols [symbol.ToString ().ToLower ()] == null) 326 | ppProcessSource = false; // set to false if symbol is not defined 327 | 328 | ppXeqStack.Push (ppProcessSource); 329 | ppDoIfSymbol = false; 330 | } 331 | else if (ppDoIfNotSymbol) // identifier following #ifnot 332 | { 333 | // do not alter ppProcessSource here if the outer scope value of ppProcessSource is false 334 | if (ppProcessSource && (bool)ppXeqStack.Peek ()) // ... value is true 335 | if (ppSymbols [symbol.ToString ().ToLower ()] != null) 336 | ppProcessSource = false; // set to false if symbol is defined 337 | 338 | ppXeqStack.Push (ppProcessSource); 339 | ppDoIfNotSymbol = false; 340 | } 341 | else 342 | Break = true; // 'regular' identifier 343 | break; 344 | case EndOfInput: 345 | Break = true; 346 | ppProcessSource = true; // force while-loop termination 347 | break; 348 | case CommentStart: 349 | if (stringMode) 350 | Break = true; 351 | 352 | if (!DoComment ("*/", true, streamInPtr.FOnLine)) 353 | ErrorMessage = "Unterminated comment starting at line " + symbol.LineNo.ToString (); 354 | 355 | break; 356 | case CommentSingle: 357 | if (stringMode) Break = true; else Break = false; 358 | DoComment ("\n", false, streamInPtr.FOnLine); 359 | eoLineCount = 1; 360 | 361 | if (seeEndOfLine) 362 | { 363 | symbol.Terminal = EndOfLine; 364 | Break = true; 365 | } 366 | 367 | break; 368 | default: 369 | if (seeEndOfLine && symbol.Terminal != EndOfLine) streamInPtr.FOnLine = false; 370 | 371 | Break = true; 372 | break; 373 | } 374 | } 375 | } while (!Break || !ppProcessSource); 376 | 377 | symbol.AbsSeqNo++; 378 | symbol.RelSeqNo++; 379 | #if showToken // a Console.Clear () will wipe out this output! 380 | IO.WriteLine ("NextSymbol[{0}] line {1}: '{2}' [{3}]", 381 | symbol.AbsSeqNo, symbol.LineNo, symbol.ToString (), symbol.ToName ()); 382 | #endif 383 | } 384 | #endregion NextSymbol 385 | } 386 | #endregion JsonParser 387 | } 388 | 389 | #region Extensions class 390 | static class JsonParserExtensions 391 | { 392 | public static bool IsHexChar (this char c) 393 | { 394 | return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); 395 | } 396 | } 397 | #endregion Extensions class 398 | } 399 | 400 | -------------------------------------------------------------------------------- /CSProlog/PG/Parser.tpl: -------------------------------------------------------------------------------- 1 | //#define LL1_tracing 2 | namespace 3 | { 4 | using System; 5 | using System.IO; 6 | using System.Text; 7 | using System.Xml; 8 | using System.Collections; 9 | using System.Collections.Generic; 10 | using System.Collections.Specialized; 11 | using System.Globalization; 12 | using System.Threading; 13 | using System.Diagnostics; 14 | using System.Security.Principal; 15 | 16 | 17 | public partial class PrologEngine 18 | { 19 | #region Parser 20 | public partial class Parser : BaseParser<> 21 | { 22 | public static readonly string VersionTimeStamp = ""; 23 | 24 | 25 | #region Terminal definition 26 | 27 | 28 | #endregion Terminal definition 29 | 30 | #region Constructor 31 | 32 | public Parser (PrologEngine engine) 33 | { 34 | this.engine = engine; 35 | ps = engine.Ps; 36 | terminalTable = engine.terminalTable; 37 | opTable = engine.OpTable; 38 | symbol = new Symbol (this); 39 | streamInPrefix = ""; 40 | streamInPreLen = 0; 41 | AddReservedOperators (); 42 | } 43 | 44 | 45 | public Parser () 46 | { 47 | terminalTable = new BaseTrie (terminalCount, false); 48 | FillTerminalTable (terminalTable); 49 | symbol = new Symbol (this); 50 | streamInPrefix = ""; 51 | streamInPreLen = 0; 52 | 53 | AddReservedOperators (); 54 | 55 | } 56 | #endregion constructor 57 | 58 | #region NextSymbol, GetSymbol 59 | protected override bool GetSymbol (TerminalSet followers, bool done, bool genXCPN<;RDPDecl/>) 60 | { 61 | string s; 62 | 63 | if (symbol.IsProcessed) NextSymbol (); 64 | 65 | symbol.SetProcessed (done); 66 | if (parseAnyText || followers.IsEmpty ()) return true; 67 | 68 | if (syntaxErrorStat) return false; 69 | 70 | if (symbol.TerminalId == ANYSYM || followers.Contains (symbol.TerminalId)) return true; 71 | 72 | switch (symbol.TerminalId) 73 | { 74 | case EndOfLine: 75 | if (seeEndOfLine) s = ""; else goto default; 76 | s = ""; 77 | break; 78 | case EndOfInput: 79 | s = ""; 80 | break; 81 | default: 82 | s = String.Format ("\"{0}\"", symbol.ToString ()); 83 | break; 84 | } 85 | 86 | s = String.Format ("*** Unexpected symbol: {0}{1}*** Expected one of: {2}", s, 87 | Environment.NewLine, terminalTable.TerminalImageSet (followers)); 88 | if (genXCPN) 89 | SyntaxError = s; 90 | else 91 | errorMessage = s; 92 | 93 | return true; 94 | } 95 | #endregion NextSymbol, GetSymbol 96 | 97 | #region PARSER PROCEDURES 98 | public override void RootCall () 99 | { 100 | 101 | } 102 | 103 | 104 | public override void Delegates () 105 | { 106 | 107 | } 108 | 109 | 110 | #endregion PARSER PROCEDURES 111 | } 112 | #endregion Parser 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /CSProlog/PG/go.bat: -------------------------------------------------------------------------------- 1 | cls 2 | 3 | for %%f in (*.grm) do (PG4main %%~nf) 4 | 5 | PAUSE 6 | -------------------------------------------------------------------------------- /CSProlog/PG/jgo.bat: -------------------------------------------------------------------------------- 1 | cls 2 | 3 | PG4main JSON 4 | 5 | REM copy Json.cs .. 6 | 7 | PAUSE 8 | -------------------------------------------------------------------------------- /CSProlog/PG/pg4main.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/CSProlog/PG/pg4main.exe -------------------------------------------------------------------------------- /CSProlog/PredDescr.cs: -------------------------------------------------------------------------------- 1 | #define enableSpying 2 | /*----------------------------------------------------------------------------------------- 3 | 4 | C#Prolog -- Copyright (C) 2007-2015 John Pool -- j.pool@ision.nl 5 | 6 | This library is free software; you can redistribute it and/or modify it under the terms of 7 | the GNU Lesser General Public License as published by the Free Software Foundation; either 8 | version 3.0 of the License, or any later version. 9 | 10 | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 11 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | See the GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl-3.0.html), or 13 | enter 'license' at the command prompt. 14 | 15 | -------------------------------------------------------------------------------------------*/ 16 | 17 | using System; 18 | using System.Collections.Generic; 19 | 20 | namespace Prolog 21 | { 22 | [Flags] 23 | public enum SpyPort : short { None = 0, Call = 1, Exit = 2, Fail = 4, Redo = 8, Full = 15 } 24 | public enum CachePort { Exit, Fail } 25 | 26 | public partial class PrologEngine 27 | { 28 | public partial class PredicateDescr 29 | { 30 | string module; // TO BE IMPLEMENTED 31 | string definitionFile; 32 | protected string functor; 33 | public string Functor { get { return functor; } } 34 | protected int arity; 35 | public int Arity { get { return arity; } } 36 | public string Name { get { return functor + '/' + arity; } } 37 | public string Key { get { return arity + functor; } } 38 | const short ARG0COUNT_MIN = 8; 39 | Dictionary arg0Index = null; // for first argument indexing 40 | ClauseNode clauseList; // start of list of clauses making up this predicate 41 | public ClauseNode ClauseList { get { return clauseList; } } 42 | ClauseNode lastCachedClause; // if the predicate is cacheable, each 'calculated' answer is inserted after this node 43 | ClauseNode clauseListEnd; // keeps track of the position of the last clause 44 | bool isDiscontiguous = false; // pertains to a single definitionFile only. A predicate must always be in a single definitionFile 45 | bool isCacheable = false; // indicates whether in principle the result of the predicate evaluation can be cached (tabled) 46 | int profileCount = 0; // number of times the predicate was called 47 | public bool IsDiscontiguous { get { return isDiscontiguous; } set { isDiscontiguous = value; } } 48 | public bool IsCacheable { get { return isCacheable; } set { isCacheable = value; } } 49 | public bool HasCachedValues { get { return lastCachedClause != null; } } 50 | public int ProfileCount { get { return profileCount; } set { profileCount = value; } } 51 | public void IncProfileCount() 52 | { 53 | profileCount++; 54 | } 55 | #if enableSpying 56 | bool spied; 57 | public bool Spied { get { return spied; } } 58 | SpyPort spyMode; 59 | public SpyPort SpyPort { get { return spyMode; } } 60 | #endif 61 | public string Module { get { return module; } set { module = value; } } 62 | public string DefinitionFile { get { return definitionFile; } } 63 | 64 | public PredicateDescr(string module, string definitionFile, string functor, int arity, ClauseNode clauseList) 65 | { 66 | this.module = module; 67 | this.definitionFile = (definitionFile == null) ? "predefined or asserted predicate" : definitionFile; 68 | this.functor = functor; 69 | this.arity = arity; 70 | #if enableSpying 71 | spyMode = SpyPort.None; 72 | #endif 73 | this.clauseList = clauseListEnd = clauseList; 74 | this.lastCachedClause = null; // no cached clauses (yet) 75 | } 76 | 77 | 78 | public void SetClauseListHead(ClauseNode c) 79 | { 80 | clauseList = clauseListEnd = c; 81 | 82 | while (clauseListEnd.NextClause != null) clauseListEnd = clauseListEnd.NextClause; 83 | 84 | DestroyFirstArgIndex(); 85 | } 86 | 87 | 88 | public void AdjustClauseListEnd() // forward clauseListEnd to the last clause 89 | { 90 | if ((clauseListEnd = clauseList) != null) 91 | while (clauseListEnd.NextClause != null) clauseListEnd = clauseListEnd.NextClause; 92 | } 93 | 94 | 95 | public void AppendToClauseList(ClauseNode c) // NextClause and ClauseListEnd are != null 96 | { 97 | clauseListEnd.NextClause = c; 98 | 99 | do 100 | clauseListEnd = clauseListEnd.NextClause; 101 | while 102 | (clauseListEnd.NextClause != null); 103 | 104 | DestroyFirstArgIndex(); 105 | } 106 | 107 | // CACHEING CURRENTLY NOT USED 108 | #region Cacheing 109 | // Cache -- analogous to asserting a fact, but specifically for cacheing. 110 | // Cached terms are inserted at the very beginning of the predicate's clause 111 | // chain, in the order in which they were determined. 112 | public void Cache(BaseTerm cacheTerm, bool succeeds) 113 | { 114 | IO.WriteLine("Cacheing {0}{1}", cacheTerm, succeeds ? null : " :- !, fail"); 115 | 116 | CachedClauseNode newCachedClause = new CachedClauseNode(cacheTerm, null, succeeds); 117 | 118 | if (lastCachedClause == null) // about to add the first cached term 119 | { 120 | newCachedClause.NextClause = clauseList; 121 | clauseList = newCachedClause; 122 | } 123 | else 124 | { 125 | newCachedClause.NextClause = lastCachedClause.NextClause; 126 | lastCachedClause.NextClause = newCachedClause; 127 | } 128 | 129 | lastCachedClause = newCachedClause; 130 | } 131 | 132 | 133 | public void Uncache() 134 | { 135 | if (HasCachedValues) // let clauseList start at the first non-cached clause again 136 | { 137 | clauseList = lastCachedClause.NextClause; 138 | lastCachedClause = null; 139 | } 140 | } 141 | #endregion Cacheing 142 | 143 | /* First-argument indexing 144 | 145 | A dictionary is maintained of clauses that have a nonvar first argument. 146 | Each predicate has its own dictionary. The functors of these first arguments are 147 | distinct (that is, in the dictionary). For predicate clauses that have identical 148 | first argument functors, only the first of these clauses is included in the 149 | dictionary. The clauses are traversed in the order in which they were read in. 150 | 151 | If a clause with a *variable* first argument is encountered, it is added 152 | to the dictionary as well, but no more entries wil be added after that. 153 | It will serve as a catch-all for instantiated arguments that do not match with 154 | any of the other dictionary entries. 155 | 156 | First-argument indexing is applied when a goal is about to be resolved. If the 157 | first argument of the goal is a bound term, it will be looked up in the 158 | dictionary. If it is found, the first clause of the defining predicate (cf. 159 | ExecuteGoalList()) is set to the dictionary entry. If it is not found, and the 160 | dictionary has a nonvar-entry, then the first clause is set to that 161 | entry. The (nonvar) goal fails if it is not found in the dictionary. 162 | 163 | First-argument indexing is not used upon backtracking. Choicepoints are simply 164 | the next clauses after the current one. 165 | 166 | Notice that this implementation of first-argument indexing is of limited use if 167 | there are many similar first arguments that are scattered throughout the 168 | predicate clauses, especially when backtracking takes place. 169 | A more sopisticated scheme could be envisaged where all similar fa-clauses are 170 | chained together. Now, for optimal use the user has to take care that all similar 171 | fa-clauses are grouped together (which seems advisable anyway). 172 | */ 173 | 174 | const bool VARARG = true; 175 | 176 | public bool CreateFirstArgIndex() 177 | { 178 | return CreateFirstArgIndex(false); // false: do not create if it already exists 179 | } 180 | 181 | 182 | public bool CreateFirstArgIndex(bool force) // Create the index if the predicate qualifies 183 | { 184 | if (arg0Index != null && !force) return false; // index already exists 185 | 186 | // Check each nextClause whether with the addition of this nextClause the predicate 187 | // still qualifies for first argument indexing. 188 | // Indexing y/n must be (re)determined after a file consult or an assert. 189 | 190 | ClauseNode c = clauseList; 191 | short arg0Count = 0; 192 | 193 | while (c != null) 194 | { 195 | if (c.Head.Arity != 0) // no first arg 196 | { 197 | arg0Count++; // Indexing not worthwile if only a few number of clauses 198 | 199 | if (c.Head.Arg(0).IsVar) break; 200 | } 201 | 202 | c = c.NextClause; 203 | } 204 | 205 | if (arg0Count < ARG0COUNT_MIN) return false; 206 | 207 | // second pass: build the index 208 | 209 | arg0Index = new Dictionary(); 210 | c = clauseList; 211 | 212 | while (c != null) 213 | { 214 | string s; 215 | 216 | BaseTerm t = c.Head.Arg(0); 217 | 218 | if (t.IsVar) 219 | { 220 | arg0Index[VARARG] = c; // stop immediately after having included the first variable 221 | 222 | break; 223 | } 224 | else if (!arg0Index.ContainsKey(s = t.FunctorToString)) 225 | arg0Index[s] = c; 226 | 227 | c = c.NextClause; 228 | } 229 | 230 | if (arg0Index.Count == 1) // e.g. c(a(1)), c(a(2)), c(a(3)), ... 231 | { 232 | arg0Index = null; 233 | 234 | return false; 235 | } 236 | else 237 | return true; 238 | } 239 | 240 | 241 | public bool IsFirstArgIndexed { get { return (arg0Index != null); } } 242 | 243 | public bool IsFirstArgMarked(ClauseNode c) 244 | { 245 | if (arg0Index == null) return false; 246 | 247 | BaseTerm t = c.Term.Arg(0); 248 | ClauseNode result; 249 | 250 | if (t.IsVar) 251 | arg0Index.TryGetValue(VARARG, out result); 252 | else 253 | arg0Index.TryGetValue(t.FunctorToString, out result); 254 | 255 | return (result == c); 256 | } 257 | 258 | 259 | public ClauseNode FirstArgNonvarClause(string arg) 260 | { 261 | ClauseNode result; 262 | arg0Index.TryGetValue(arg, out result); 263 | 264 | return result; 265 | } 266 | 267 | 268 | public ClauseNode FirstArgVarClause() 269 | { 270 | ClauseNode result; 271 | arg0Index.TryGetValue(VARARG, out result); 272 | 273 | return result; 274 | } 275 | 276 | 277 | public void DestroyFirstArgIndex() 278 | { 279 | arg0Index = null; 280 | } 281 | 282 | //public void DumpClauseList() 283 | //{ 284 | // NextClause c = clauseList; 285 | 286 | // while (c != null) 287 | // { 288 | // IO.WriteLine("DumpValues -- {0}", c); 289 | // c = c.NextClause; 290 | // } 291 | //} 292 | 293 | public override string ToString() 294 | { 295 | return string.Format("pd[{0}/{1} clauselist {2}]", functor, arity, clauseList); 296 | } 297 | 298 | 299 | #if enableSpying 300 | public void SetSpy(bool enabled, string functor, int arity, SpyPort setPorts, bool warn) 301 | { 302 | string spySet = "["; 303 | 304 | if (enabled) 305 | { 306 | spied = true; 307 | spyMode = SpyPort.None; 308 | 309 | foreach (SpyPort port in Enum.GetValues(typeof(SpyPort))) 310 | if (setPorts > 0 && (setPorts | port) == setPorts) 311 | { 312 | spyMode |= port; 313 | 314 | if (port != SpyPort.Full) 315 | spySet += port.ToString() + (port == SpyPort.Redo ? "]" : ","); 316 | } 317 | 318 | if (setPorts != SpyPort.None) 319 | IO.Message("Spying {0} enabled for {1}/{2}", spySet, functor, arity); 320 | } 321 | else if (spied) // nospy 322 | { 323 | spied = false; 324 | IO.Message("Spying disabled for {0}/{1}", functor, arity); 325 | } 326 | else if (warn) 327 | IO.Message("There was no spypoint on {0}/{1}", functor, arity); 328 | } 329 | 330 | 331 | public void ShowSpypoint() 332 | { 333 | if (spyMode == SpyPort.None) return; 334 | 335 | string spySet = "["; 336 | 337 | foreach (SpyPort port in Enum.GetValues(typeof(SpyPort))) 338 | if (port > 0 && port != SpyPort.Full && (spyMode | port) == spyMode) 339 | spySet += port.ToString() + (port == SpyPort.Redo ? "]" : ","); 340 | 341 | IO.WriteLine("{0}/{1}: {2}", Functor, Arity, spySet); 342 | } 343 | #endif 344 | } 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /CSProlog/TermArray.cs: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------------------- 2 | 3 | C#Prolog -- Copyright (C) 2007-2015 John Pool -- j.pool@ision.nl 4 | 5 | This library is free software; you can redistribute it and/or modify it under the terms of 6 | the GNU Lesser General Public License as published by the Free Software Foundation; either 7 | version 3.0 of the License, or any later version. 8 | 9 | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | See the GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl-3.0.html), or 12 | enter 'license' at the command prompt. 13 | 14 | -------------------------------------------------------------------------------------------*/ 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | using System.Text; 19 | 20 | // Arrays: not in this version. The whole concept needs to be thought over more carefully. 21 | 22 | namespace Prolog 23 | { 24 | public partial class PrologEngine 25 | { 26 | // untested code 27 | #region TermArray 28 | public class TermArray 29 | { 30 | string name; 31 | int[] dimensions; 32 | // Any array (i.e. with an arbitrary number of subscripts) is mapped to a one-dimensional 33 | // one (baseArray). In doing so, it is possible to accomodate arrays with an arbitrary 34 | // number of subscripts. 35 | BaseTerm[] baseArray; 36 | public int Rank { get { return dimensions.Length; } } 37 | public string Name { get { return name; } } 38 | 39 | public TermArray(string name, int[] dimensions) 40 | { 41 | this.name = name; 42 | this.dimensions = dimensions; 43 | int length = 1; 44 | 45 | for (int i = 0; i < dimensions.Length; i++) 46 | { 47 | if (dimensions[i] <= 0) 48 | IO.Error("Dimension {0} of array '{1}' has illegal value {2}", i, name, dimensions[i]); 49 | 50 | length *= dimensions[i]; 51 | } 52 | 53 | baseArray = new BaseTerm[length]; 54 | } 55 | 56 | public BaseTerm GetEntry(int[] subscripts) // subscripts are zero-based 57 | { 58 | return baseArray[CalculateOffset(subscripts)]; 59 | } 60 | 61 | public void SetEntry(int[] subscripts, BaseTerm t) 62 | { 63 | baseArray[CalculateOffset(subscripts)] = t; 64 | } 65 | 66 | // CalculateOffset calculates the mapping of [i1, i2, ..., iN] to the index in this 1-D array 67 | int CalculateOffset(int[] subscripts) // f(i1, i2, ..., iN) => 0 .. d1*d2*...*dN-1 68 | { 69 | for (int i = 0; i < subscripts.Length; i++) 70 | if (subscripts[i] < 0 || subscripts[i] >= dimensions[i]) 71 | IO.Error("Value of index {0} is {1} but must be in the range 0..{2}", 72 | i, subscripts[i], dimensions[i] - 1); 73 | 74 | int offset = subscripts[0]; 75 | 76 | for (int i = 1; i < subscripts.Length; i++) 77 | offset = offset * dimensions[i] + subscripts[i]; 78 | 79 | return offset; 80 | } 81 | } 82 | #endregion TermArray 83 | 84 | #region ArrayVariable 85 | public class ArrayVariable : NamedVariable 86 | { 87 | TermArray ta; 88 | List subscripts; 89 | 90 | public ArrayVariable(string name, TermArray ta, ListTerm subscripts) 91 | { 92 | this.ta = ta; 93 | this.name = ta.Name; 94 | this.subscripts = subscripts.ToTermList(); 95 | 96 | if (this.subscripts.Count != ta.Rank) 97 | IO.Error("Wrong number of subscripts for '{0}': expected {1}, got {2}", 98 | name, ta.Rank, this.subscripts.Count); 99 | } 100 | 101 | public override string ToWriteString(int level) 102 | { 103 | StringBuilder sb = new StringBuilder(name); 104 | bool first = true; 105 | 106 | foreach (BaseTerm t in subscripts) 107 | { 108 | if (first) first = false; else sb.Append(CommaAtLevel(level)); 109 | 110 | sb.Append((t.IsGround ? t.Eval() : t).ToString()); // at end of query vs. any other situation 111 | } 112 | 113 | return sb.ToString(); 114 | } 115 | } 116 | #endregion ArrayVariable 117 | 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /CSProlog/TermNodeList.cs: -------------------------------------------------------------------------------- 1 | //#define arg1index // if (un)defined, do the same in PredStorage.cs !!! 2 | /*----------------------------------------------------------------------------------------- 3 | 4 | C#Prolog -- Copyright (C) 2007-2015 John Pool -- j.pool@ision.nl 5 | 6 | This library is free software; you can redistribute it and/or modify it under the terms of 7 | the GNU Lesser General Public License as published by the Free Software Foundation; either 8 | version 3.0 of the License, or any later version. 9 | 10 | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 11 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | See the GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl-3.0.html), or 13 | enter 'license' at the command prompt. 14 | 15 | -------------------------------------------------------------------------------------------*/ 16 | 17 | using System; 18 | using System.Text; 19 | 20 | namespace Prolog 21 | { 22 | /* 23 | -------- 24 | TermNode 25 | -------- 26 | 27 | A TermNode serves two purposes: 28 | - to store the goals of a command 29 | - to store predicates (clauses) 30 | 31 | A goal is constructed as a simple chained term of TermNodes. This makes it easy 32 | (and also more efficient in terms of GC) to revert to a previous state upon backtracking 33 | (in contrast to i.e. an ArrayList). 34 | 35 | A predicate consists of one or more clauses. A clause consist of a head and optionally a 36 | body. A head is a term, the body is a sequence of terms. A predicate is stored as a chain 37 | of TermNodes, where each TermNode represents a clause. These TermNodes are linked via the 38 | nextClause field. In each nextClause/TermNode the clause head is stored in term, and the 39 | clause body (which may be null) in NextNode. 40 | 41 | */ 42 | 43 | 44 | public partial class PrologEngine 45 | { 46 | #region TermNode 47 | public class TermNode 48 | { 49 | BI builtinId = BI.none; 50 | protected BaseTerm term; // for a NextClause: predicate head 51 | protected TermNode nextNode = null; // next node in the chain 52 | protected ClauseNode nextClause = null; // next predicate clause (advanced upon backtracking) 53 | protected PredicateDescr predDescr; // points to the predicate definition for term 54 | public BaseTerm Head { get { return term; } set { term = value; } } 55 | public ClauseNode NextClause { get { return nextClause; } set { nextClause = value; } } 56 | protected int level = 0; // debugging and tracing (for indentation) 57 | 58 | #region public properties 59 | public int Level { get { return level; } set { level = value; } } 60 | public BaseTerm Term { get { return term; } } 61 | public TermNode NextNode { get { return nextNode; } set { nextNode = value; } } 62 | public TermNode NextGoal { get { return nextNode; } set { nextNode = value; } } 63 | public bool Spied { get { return PredDescr == null ? false : PredDescr.Spied; } } 64 | public SpyPort SpyPort { get { return PredDescr == null ? SpyPort.None : PredDescr.SpyPort; } } 65 | public BI BuiltinId { get { return builtinId; } } 66 | public PredicateDescr PredDescr { get { return predDescr; } set { predDescr = value; } } 67 | #endregion 68 | 69 | public TermNode() 70 | { 71 | } 72 | 73 | 74 | public TermNode(BaseTerm term, PredicateDescr predDescr) 75 | { 76 | this.predDescr = predDescr; 77 | this.term = term; 78 | } 79 | 80 | 81 | public TermNode(BaseTerm term, PredicateDescr predDescr, int level) 82 | { 83 | this.term = term; 84 | this.predDescr = predDescr; 85 | this.level = level; 86 | } 87 | 88 | 89 | public TermNode(string tag) // builtin predicates 90 | { 91 | try 92 | { 93 | builtinId = (BI)Enum.Parse(typeof(BI), tag, false); 94 | } 95 | catch 96 | { 97 | IO.Error("Bootstrap.cs: unknown BI enum value '{0}'", tag); 98 | } 99 | } 100 | 101 | 102 | public TermNode(BaseTerm term, TermNode nextNode) 103 | { 104 | this.term = term; 105 | this.nextNode = nextNode; 106 | } 107 | 108 | 109 | // put the predicate definition (if found) into the TermNode if it is not already there 110 | public bool FindPredicateDefinition(PredicateTable predicateTable) 111 | { 112 | if (predDescr == null) 113 | { 114 | if ((predDescr = predicateTable[term.Key]) == null) 115 | return false; 116 | } 117 | 118 | #if arg1index // first-argument indexing enabled 119 | BaseTerm arg; 120 | 121 | // caching would disturb the search process (since caching does not 122 | // cause the arg0Index to be rebuild, since this might be to costly) 123 | if (predDescr.IsFirstArgIndexed && !predDescr.HasCachedValues) 124 | { 125 | if ((arg = term.Arg (0)).IsVar) 126 | nextClause = predDescr.FirstArgVarClause (); 127 | else // not a variable 128 | { 129 | nextClause = predDescr.FirstArgNonvarClause (arg.FunctorToString); 130 | 131 | // check whether there is an indexed var clause 132 | if (nextClause == null) 133 | nextClause = predDescr.FirstArgVarClause (); 134 | 135 | // if the above failed, the entire predicate fails (no unification possible) 136 | if (nextClause == null) 137 | nextClause = ClauseNode.FAIL; 138 | } 139 | 140 | if (nextClause == null) 141 | nextClause = predDescr.ClauseList; 142 | } 143 | else // not indexed 144 | #endif 145 | nextClause = predDescr.ClauseList; 146 | 147 | return true; 148 | } 149 | 150 | 151 | public void Append(BaseTerm t) 152 | { 153 | if (term == null) // empty term 154 | { 155 | term = t; 156 | 157 | return; 158 | } 159 | 160 | TermNode tail = this; 161 | TermNode next = nextNode; 162 | 163 | while (next != null) 164 | { 165 | tail = next; 166 | next = next.nextNode; 167 | } 168 | 169 | tail.nextNode = new TermNode(t, (PredicateDescr)null); 170 | } 171 | 172 | 173 | public TermNode Append(TermNode t) 174 | { 175 | TermNode tail = this; 176 | TermNode next = nextNode; 177 | 178 | while (next != null) // get the last TermNode 179 | { 180 | tail = next; 181 | next = next.nextNode; 182 | } 183 | 184 | tail.nextNode = t; 185 | 186 | return this; 187 | } 188 | 189 | 190 | public void Clear() 191 | { 192 | term = null; 193 | nextNode = null; 194 | nextClause = null; 195 | level = 0; 196 | } 197 | 198 | 199 | public BaseTerm TermSeq() 200 | { 201 | return (NextNode == null) 202 | ? Term // last term of TermNode 203 | : new OperatorTerm(CommaOpDescr, Term, NextNode.TermSeq()); 204 | } 205 | 206 | 207 | public override string ToString() 208 | { 209 | StringBuilder sb = new StringBuilder(); 210 | bool first = true; 211 | int indent = 2; 212 | TermNode tn = this; 213 | BaseTerm t; 214 | 215 | while (tn != null) 216 | { 217 | if ((t = tn.term) is TryOpenTerm) 218 | { 219 | if (!first) sb.Append(','); 220 | 221 | sb.AppendFormat("{0}{1}TRY{0}{1}(", Environment.NewLine, Spaces(2 * indent++)); 222 | first = true; 223 | } 224 | else if (t is CatchOpenTerm) 225 | { 226 | CatchOpenTerm co = (CatchOpenTerm)t; 227 | string msgVar = (co.MsgVar is AnonymousVariable) ? null : co.MsgVar.Name; 228 | string comma = (co.ExceptionClass == null || msgVar == null) ? null : ", "; 229 | 230 | sb.AppendFormat("{0}{1}){0}{1}CATCH {2}{3}{4}{0}{1}(", 231 | Environment.NewLine, Spaces(2 * (indent - 1)), co.ExceptionClass, comma, msgVar); 232 | first = true; 233 | } 234 | else if (t == TC_CLOSE) 235 | { 236 | sb.AppendFormat("{0}{1})", Environment.NewLine, Spaces(2 * --indent)); 237 | first = false; 238 | } 239 | else 240 | { 241 | if (first) first = false; else sb.Append(','); 242 | 243 | sb.AppendFormat("{0}{1}{2}", Environment.NewLine, Spaces(2 * indent), t); 244 | } 245 | 246 | tn = tn.nextNode; 247 | } 248 | 249 | return sb.ToString(); 250 | } 251 | } 252 | #endregion TermNode 253 | 254 | #region clause 255 | // the terms (connected by NextNode) of a single clause 256 | public class ClauseNode : TermNode 257 | { 258 | public ClauseNode() 259 | { 260 | } 261 | 262 | public ClauseNode(BaseTerm t, TermNode body) 263 | : base(t, body) 264 | { 265 | } 266 | 267 | 268 | public override string ToString() 269 | { 270 | string NL = Environment.NewLine; 271 | 272 | StringBuilder sb = new StringBuilder(NL + term.ToString()); 273 | 274 | bool first = true; 275 | TermNode tl = nextNode; 276 | 277 | if (tl == null) return sb.ToString() + '.' + NL; 278 | 279 | while (true) 280 | { 281 | if (first) sb.Append(" :-"); 282 | 283 | sb.Append(NL + " " + tl.Term); 284 | 285 | if ((tl = tl.NextNode) == null) 286 | return sb.ToString() + '.' + NL; 287 | else if (!first) 288 | sb.AppendFormat(","); 289 | 290 | first = false; 291 | } 292 | } 293 | 294 | 295 | public static ClauseNode FAIL = new ClauseNode(BaseTerm.FAIL, null); 296 | } 297 | 298 | 299 | // CACHEING CURRENTLY NOT USED 300 | public class CachedClauseNode : ClauseNode 301 | { 302 | bool succeeds; // indicates whether the cached fact results in a failure or in a success 303 | // i.e. in doing so fib(1,9999) will effecively be cached as 'fib( 1, 9999) :- !, fail' 304 | // (the ! is necessary to prevent the resolution process from recalculating the same result 305 | // again). 306 | public bool Succeeds { get { return succeeds; } } 307 | 308 | public CachedClauseNode(BaseTerm t, TermNode body, bool succeeds) : base(t, body) 309 | { 310 | this.succeeds = succeeds; 311 | } 312 | } 313 | #endregion clause 314 | 315 | #region SpyPoint 316 | // pushed on the VarStack to detect failure, inserted in the saveGoal to detect Exit. 317 | class SpyPoint : TermNode // TermNode only used as at-compatible vehicle for port and saveGoal 318 | { 319 | SpyPort port; 320 | public SpyPort Port { get { return port; } } 321 | TermNode saveGoal; 322 | public TermNode SaveGoal { get { return saveGoal; } } 323 | 324 | public SpyPoint(SpyPort p, TermNode g) 325 | : base() 326 | { 327 | port = p; 328 | saveGoal = g; 329 | level = g.Level; 330 | } 331 | 332 | public void Kill() 333 | { 334 | port = SpyPort.None; 335 | } 336 | 337 | public override string ToString() 338 | { 339 | return "[" + port + "-spypoint] " + saveGoal.Term.ToString() + " ..."; 340 | } 341 | } 342 | #endregion SpyPoint 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /CSProlog/TermSet.cs: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------------------- 2 | 3 | C#Prolog -- Copyright (C) 2007-2015 John Pool -- j.pool@ision.nl 4 | 5 | This library is free software; you can redistribute it and/or modify it under the terms of 6 | the GNU Lesser General Public License as published by the Free Software Foundation; either 7 | version 3.0 of the License, or any later version. 8 | 9 | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | See the GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl-3.0.html), or 12 | enter 'license' at the command prompt. 13 | 14 | -------------------------------------------------------------------------------------------*/ 15 | 16 | using System.Collections.Generic; 17 | 18 | namespace Prolog 19 | { 20 | public enum DupMode { DupIgnore, DupAccept, DupError }; 21 | 22 | public partial class PrologEngine 23 | { 24 | public class BaseTermSet : List 25 | { 26 | DupMode dupMode; 27 | 28 | public BaseTermSet() 29 | { 30 | dupMode = DupMode.DupAccept; 31 | } 32 | 33 | 34 | public BaseTermSet(DupMode dm) 35 | { 36 | dupMode = dm; 37 | } 38 | 39 | 40 | public BaseTermSet(BaseTerm list) 41 | { 42 | while (list.Arity == 2) 43 | { 44 | Add(list.Arg(0)); 45 | list = list.Arg(1); 46 | } 47 | } 48 | 49 | 50 | public void Insert(BaseTerm termToInsert) 51 | { 52 | int i = BinarySearch(termToInsert); 53 | 54 | if (i >= 0) // found 55 | { 56 | if (dupMode == DupMode.DupAccept) Insert(i, termToInsert); 57 | } 58 | else 59 | Insert(~i, termToInsert); 60 | } 61 | 62 | 63 | public ListTerm ToList() 64 | { 65 | ListTerm t = ListTerm.EMPTYLIST; 66 | 67 | for (int i = Count - 1; i >= 0; i--) 68 | t = new ListTerm(this[i], t); // [a0, a0, ...] 69 | 70 | return t; 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Docu/Covington-NL-book.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/Docu/Covington-NL-book.zip -------------------------------------------------------------------------------- /Docu/Edinburgh-style IO.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/Docu/Edinburgh-style IO.doc -------------------------------------------------------------------------------- /Docu/HistoryOfProlog.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/Docu/HistoryOfProlog.pdf -------------------------------------------------------------------------------- /Docu/KdeBosschere-parser.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/Docu/KdeBosschere-parser.zip -------------------------------------------------------------------------------- /Docu/KdeBosschere-prolog.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/Docu/KdeBosschere-prolog.pdf -------------------------------------------------------------------------------- /Docu/Standard Operators.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/Docu/Standard Operators.doc -------------------------------------------------------------------------------- /Docu/prolog-digital.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/Docu/prolog-digital.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /PL.NETcore/Main.cs: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------------------- 2 | 3 | C#Prolog -- Copyright (C) 2007-2014 John Pool -- j.pool@ision.nl 4 | 5 | This library is free software; you can redistribute it and/or modify it under the terms of 6 | the GNU General Public License as published by the Free Software Foundation; either version 7 | 2 of the License, or any later version. 8 | 9 | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | See the GNU General Public License for details, or enter 'license.' at the command prompt. 12 | 13 | -------------------------------------------------------------------------------------------*/ 14 | 15 | using System; 16 | using System.Text; 17 | using System.Runtime.InteropServices; 18 | 19 | namespace Prolog 20 | { 21 | class PrologParser 22 | { 23 | [STAThread] 24 | public static void Main(string[] args) 25 | { 26 | PrologEngine e = null; 27 | 28 | try 29 | { 30 | e = new PrologEngine(new DosIO(), persistentCommandHistory: false); 31 | 32 | // ProcessArgs -- for batch processing. Can be left out if not used 33 | //if (e.ProcessArgs (args, false)) return; 34 | 35 | SetPreferredConsoleProperties(e); 36 | Console.Title = "C#Prolog command window"; 37 | Console.WriteLine(PrologEngine.IntroText); 38 | Console.WriteLine("\r\n--- Enter !! for command history, help for a list of all commands"); 39 | 40 | //if (Engine.ConfigSettings.InitialConsultFile != null) // set in CSProlog.exe.config 41 | // e.Consult (Engine.ConfigSettings.InitialConsultFile); // any additional initialisations 42 | 43 | while (!e.Halted) 44 | { 45 | Console.Write(e.Prompt); 46 | e.Query = ReadQuery(); 47 | 48 | // Use e.GetFirstSolution instead of the loop below if you want the first solution only. 49 | //Console.Write (e.GetFirstSolution (e.Query)); 50 | 51 | foreach (PrologEngine.ISolution s in e.SolutionIterator) 52 | { 53 | // In order to get the individual variables: 54 | //foreach (Engine.IVarValue varValue in s.VarValuesIterator) 55 | // { Console.WriteLine (varValue.Value.To ()); } // or ToString () etc. 56 | Console.Write(s); 57 | 58 | if (s.IsLast || !UserWantsMore()) break; 59 | } 60 | 61 | Console.WriteLine(); 62 | } 63 | } 64 | catch (Exception x) 65 | { 66 | Console.WriteLine("Error while initializing Prolog Engine. Message was:\r\n{0}", 67 | x.GetBaseException().Message + Environment.NewLine + x.StackTrace); 68 | Console.ReadLine(); 69 | } 70 | finally 71 | { 72 | if (e != null) e.PersistCommandHistory(); // cf. CSProlog.exe.config 73 | } 74 | } 75 | 76 | 77 | #region Console I/O 78 | static void SetPreferredConsoleProperties(PrologEngine e) 79 | { 80 | Console.ForegroundColor = ConsoleColor.DarkBlue; 81 | Console.BackgroundColor = ConsoleColor.White; 82 | Console.Clear(); // applies the background color to the *entire* window background 83 | 84 | // TODO: The following line is supposed to prevent ^C from exiting the application - it doesn't work for linux 85 | Console.CancelKeyPress += new ConsoleCancelEventHandler(e.Console_CancelKeyPress); 86 | } 87 | 88 | static string ReadQuery() 89 | { 90 | StringBuilder sb = new StringBuilder(); 91 | string line; 92 | 93 | while (true) 94 | { 95 | if ((line = System.ReadLine.Read()) == null) 96 | { 97 | sb.Length = 0; 98 | 99 | break; 100 | } 101 | else 102 | { 103 | sb.AppendLine(line); 104 | 105 | if (line.EndsWith("/") || line.StartsWith("!") || line.EndsWith(".")) 106 | break; 107 | 108 | Console.Write("| "); 109 | } 110 | } 111 | 112 | ReadLine.AddHistory(sb.ToString().TrimEnd(Environment.NewLine.ToCharArray())); 113 | return sb.ToString(); 114 | } 115 | 116 | 117 | static bool UserWantsMore() 118 | { 119 | Console.Write(" more? (y/n) "); 120 | char response = Console.ReadKey().KeyChar; 121 | 122 | if (response == 'y' || response == ';') 123 | { 124 | Console.WriteLine(); 125 | 126 | return true; 127 | } 128 | 129 | return false; 130 | } 131 | #endregion 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /PL.NETcore/PL.NETcore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /PLd/Main.cs: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------------------- 2 | 3 | C#Prolog -- Copyright (C) 2007-2014 John Pool -- j.pool@ision.nl 4 | 5 | This library is free software; you can redistribute it and/or modify it under the terms of 6 | the GNU General Public License as published by the Free Software Foundation; either version 7 | 2 of the License, or any later version. 8 | 9 | This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | See the GNU General Public License for details, or enter 'license.' at the command prompt. 12 | 13 | -------------------------------------------------------------------------------------------*/ 14 | 15 | using System; 16 | using System.Text; 17 | 18 | namespace Prolog 19 | { 20 | class PrologParser 21 | { 22 | [STAThread] 23 | public static void Main(string[] args) 24 | { 25 | PrologEngine e = null; 26 | 27 | try 28 | { 29 | e = new PrologEngine(new DosIO()); 30 | 31 | // ProcessArgs -- for batch processing. Can be left out if not used 32 | if (e.ProcessArgs(args, false)) return; 33 | 34 | SetPreferredConsoleProperties(e); 35 | Console.Title = "C#Prolog command window"; 36 | Console.WriteLine(PrologEngine.IntroText); 37 | Console.WriteLine("\r\n--- Enter !! for command history, help for a list of all commands"); 38 | 39 | //if (Engine.ConfigSettings.InitialConsultFile != null) // set in CSProlog.exe.config 40 | // e.Consult (Engine.ConfigSettings.InitialConsultFile); // any additional initialisations 41 | 42 | while (!e.Halted) 43 | { 44 | Console.Write(e.Prompt); 45 | e.Query = ReadQuery(); 46 | 47 | // Use e.GetFirstSolution instead of the loop below if you want the first solution only. 48 | //Console.Write (e.GetFirstSolution (e.Query)); 49 | 50 | foreach (PrologEngine.ISolution s in e.SolutionIterator) 51 | { 52 | // In order to get the individual variables: 53 | //foreach (Engine.IVarValue varValue in s.VarValuesIterator) 54 | // { Console.WriteLine (varValue.Value.To ()); } // or ToString () etc. 55 | Console.Write(s); 56 | 57 | if (s.IsLast || !UserWantsMore()) break; 58 | } 59 | 60 | Console.WriteLine(); 61 | } 62 | } 63 | catch (Exception x) 64 | { 65 | Console.WriteLine("Error while initializing Prolog Engine. Message was:\r\n{0}", 66 | x.GetBaseException().Message + Environment.NewLine + x.StackTrace); 67 | Console.ReadLine(); 68 | } 69 | finally 70 | { 71 | if (e != null) e.PersistCommandHistory(); // cf. CSProlog.exe.config 72 | } 73 | } 74 | 75 | 76 | #region Console I/O 77 | static void SetPreferredConsoleProperties(PrologEngine e) 78 | { 79 | Console.ForegroundColor = ConsoleColor.DarkBlue; 80 | Console.BackgroundColor = ConsoleColor.White; 81 | Console.Clear(); // applies the background color to the *entire* window background 82 | 83 | // The following line prevents ^C from exiting the application 84 | Console.CancelKeyPress += new ConsoleCancelEventHandler(e.Console_CancelKeyPress); 85 | } 86 | 87 | static string ReadQuery() 88 | { 89 | StringBuilder sb = new StringBuilder(); 90 | string line; 91 | 92 | while (true) 93 | { 94 | if ((line = Console.ReadLine()) == null) 95 | { 96 | sb.Length = 0; 97 | 98 | break; 99 | } 100 | else 101 | { 102 | sb.AppendLine(line); 103 | 104 | if (line.EndsWith("/") || line.StartsWith("!") || line.EndsWith(".")) break; 105 | 106 | Console.Write("| "); 107 | } 108 | } 109 | 110 | return sb.ToString(); 111 | } 112 | 113 | 114 | static bool UserWantsMore() 115 | { 116 | Console.Write(" more? (y/n) "); 117 | char response = Console.ReadKey().KeyChar; 118 | 119 | if (response == 'y' || response == ';') 120 | { 121 | Console.WriteLine(); 122 | 123 | return true; 124 | } 125 | 126 | return false; 127 | } 128 | #endregion 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /PLd/PLd.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.21022 7 | 2.0 8 | {B7438FBF-6E46-4065-A60B-1B1CA2AC9875} 9 | Exe 10 | Properties 11 | Prolog 12 | PLd 13 | v3.5 14 | 512 15 | 16 | 17 | 18 | 19 | 3.5 20 | 21 | 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | x86 30 | 31 | 32 | pdbonly 33 | true 34 | bin\Debug\ 35 | TRACE 36 | prompt 37 | 4 38 | 39 | 40 | 41 | 42 | 3.5 43 | 44 | 45 | 3.5 46 | 47 | 48 | 3.5 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {6a947b78-96d1-45f2-bb9f-036586bab544} 60 | CSProlog 61 | 62 | 63 | 64 | 71 | -------------------------------------------------------------------------------- /PLd/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle ("DosBox")] 9 | [assembly: AssemblyDescription ("")] 10 | [assembly: AssemblyConfiguration ("")] 11 | [assembly: AssemblyCompany ("Omnext bv")] 12 | [assembly: AssemblyProduct ("DosBox")] 13 | [assembly: AssemblyCopyright ("Copyright © Omnext bv 2011")] 14 | [assembly: AssemblyTrademark ("")] 15 | [assembly: AssemblyCulture ("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible (false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid ("3cebd261-0173-453c-825a-ade52212c8c7")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion ("1.0.0.0")] 36 | [assembly: AssemblyFileVersion ("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PLw/MainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Threading; 7 | using System.Drawing; 8 | using System.Text; 9 | using System.IO; 10 | using System.Windows.Forms; 11 | using System.Runtime.CompilerServices; 12 | using Prolog; 13 | 14 | namespace Prolog 15 | { 16 | public enum GuiAction 17 | { 18 | None, ReadStart, ReadEnd, ReadLn, ReadCh, Write, WriteLn, NewLn, Clear, Reset, BtnsOn, BtnsOff 19 | } 20 | 21 | public partial class MainForm : Form 22 | { 23 | #region WinIO. Base class for Windows IO 24 | public class WinIO : BasicIo 25 | { 26 | BackgroundWorker bgw; 27 | ManualResetEvent semaGetInput; 28 | TextBox tbInput; 29 | Queue charBuffer; 30 | 31 | public WinIO (BackgroundWorker bgw, ManualResetEvent semaGetInput, 32 | TextBox tbInput, Queue charBuffer) 33 | { 34 | this.bgw = bgw; 35 | this.semaGetInput = semaGetInput; 36 | this.tbInput = tbInput; 37 | this.charBuffer = charBuffer; 38 | } 39 | 40 | 41 | public override string ReadLine () 42 | { 43 | try 44 | { 45 | bgw.DoGuiAction (GuiAction.ReadStart); 46 | bgw.DoGuiAction (GuiAction.ReadLn); 47 | semaGetInput.WaitOne (); // wait until text has been entered in tbInput 48 | 49 | return tbInput.Text; 50 | } 51 | finally 52 | { 53 | semaGetInput.Reset (); 54 | bgw.DoGuiAction (GuiAction.ReadEnd); 55 | } 56 | } 57 | 58 | 59 | public override int ReadChar () 60 | { 61 | if (charBuffer.Count == 0) 62 | try 63 | { 64 | bgw.DoGuiAction (GuiAction.ReadStart); 65 | bgw.DoGuiAction (GuiAction.ReadCh); 66 | semaGetInput.WaitOne (); // wait until charBuffer is not empty 67 | } 68 | finally 69 | { 70 | semaGetInput.Reset (); 71 | bgw.DoGuiAction (GuiAction.ReadEnd); 72 | } 73 | 74 | return charBuffer.Dequeue (); 75 | } 76 | 77 | 78 | public override void Write (string s) 79 | { 80 | bgw.DoGuiAction (GuiAction.Write, s); 81 | } 82 | 83 | 84 | public override void WriteLine (string s) 85 | { 86 | bgw.DoGuiAction (GuiAction.WriteLn, s); 87 | } 88 | 89 | 90 | public override void WriteLine () 91 | { 92 | bgw.DoGuiAction (GuiAction.NewLn); 93 | } 94 | 95 | 96 | public override void Clear () 97 | { 98 | bgw.DoGuiAction (GuiAction.Clear); 99 | } 100 | 101 | 102 | public override void Reset () 103 | { 104 | bgw.DoGuiAction (GuiAction.Reset); 105 | } 106 | } 107 | #endregion WinIO 108 | 109 | #region BatIO. Base class for batch IO. Input not possible, output written to log file 110 | public class BatIO : BasicIo 111 | { 112 | StreamWriter sw = null; 113 | string pathName; 114 | string fileName; 115 | bool fileOpen; 116 | 117 | public BatIO () 118 | { 119 | fileOpen = false; // file will be created if there is any output at all 120 | } 121 | 122 | private void CreateFile () 123 | { 124 | try 125 | { 126 | pathName = 127 | Path.GetDirectoryName (Application.ExecutablePath) + 128 | Path.DirectorySeparatorChar + "batchlogs" + Path.DirectorySeparatorChar; 129 | 130 | if (!Directory.Exists (pathName)) Directory.CreateDirectory (pathName); 131 | } 132 | catch (Exception e) 133 | { 134 | MessageBox.Show (string.Format ("Error creating directory '{0}'.\r\nMessage was:\r\n{1}", 135 | pathName, e.Message)); 136 | } 137 | 138 | try 139 | { 140 | fileName = pathName + "PLw" + DateTime.Now.ToString ("yyyy-MM-dd@HH.mm.ss") + ".log"; 141 | sw = new StreamWriter (fileName); 142 | } 143 | catch (Exception e) 144 | { 145 | MessageBox.Show (string.Format ("Error opening log file '{0}'.\r\nMessage was:\r\n{1}", 146 | fileName, e.Message)); 147 | } 148 | 149 | fileOpen = true; 150 | } 151 | 152 | 153 | public override string ReadLine () 154 | { 155 | return ""; 156 | } 157 | 158 | 159 | public override int ReadChar () 160 | { 161 | return 0; 162 | } 163 | 164 | 165 | public override void Write (string s) 166 | { 167 | if (!fileOpen) CreateFile (); 168 | 169 | sw.Write (s); 170 | } 171 | 172 | 173 | public override void WriteLine (string s) 174 | { 175 | if (!fileOpen) CreateFile (); 176 | 177 | sw.WriteLine (s); 178 | } 179 | 180 | 181 | public override void WriteLine () 182 | { 183 | if (!fileOpen) CreateFile (); 184 | 185 | sw.WriteLine (); 186 | } 187 | 188 | 189 | public override void Clear () 190 | { 191 | } 192 | 193 | 194 | public override void Reset () 195 | { 196 | } 197 | 198 | 199 | public void Close () 200 | { 201 | if (sw != null) sw.Close (); 202 | } 203 | } 204 | #endregion BatIO 205 | 206 | Prolog.PrologEngine.ApplicationStorage persistentSettings; 207 | PrologEngine pe; 208 | bool? stop; 209 | ManualResetEvent semaMoreStop; 210 | ManualResetEvent semaGetInput; 211 | WinIO winIO; 212 | Queue charBuffer; 213 | GuiAction readMode; // for distinguishing between various ways of reading input 214 | 215 | public MainForm () 216 | { 217 | InitializeComponent (); 218 | Text = "C# Prolog -- basic Windows version"; 219 | persistentSettings = new PrologEngine.ApplicationStorage (); 220 | stop = null; 221 | semaGetInput = new ManualResetEvent (false); 222 | charBuffer = new Queue (); 223 | winIO = new WinIO (bgwExecuteQuery, semaGetInput, tbInput, charBuffer); 224 | bgwExecuteQuery.DoGuiAction (GuiAction.BtnsOff); 225 | pe = new PrologEngine (winIO); 226 | readMode = GuiAction.None; 227 | } 228 | 229 | 230 | void btnXeqQuery_Click (object sender, EventArgs e) 231 | { 232 | if (bgwExecuteQuery.IsBusy && !bgwExecuteQuery.CancellationPending) return; 233 | 234 | //tbAnswer.Clear (); 235 | btnCancelQuery.Enabled = true; 236 | btnMore.Enabled = btnStop.Enabled = false; 237 | lblMoreOrStop.Visible = false; 238 | bgwExecuteQuery.RunWorkerAsync (rtbQuery.Text.AddEndDot ()); 239 | } 240 | 241 | 242 | void bgwExecuteQuery_DoWork (object sender, DoWorkEventArgs e) 243 | { 244 | try 245 | { 246 | pe.Query = e.Argument as string; 247 | semaMoreStop = new ManualResetEvent (false); 248 | 249 | foreach (PrologEngine.ISolution s in pe.SolutionIterator) 250 | { 251 | winIO.WriteLine ("{0}{1}", s, (s.IsLast ? null : ";")); 252 | 253 | if (s.IsLast) break; 254 | 255 | bool stop; 256 | WaitForMoreOrStopPressed (out stop); 257 | semaMoreStop.Reset (); 258 | 259 | if (stop) break; 260 | } 261 | } 262 | finally 263 | { 264 | pe.PersistCommandHistory (); 265 | } 266 | } 267 | 268 | 269 | void WaitForMoreOrStopPressed (out bool halt) 270 | { 271 | bgwExecuteQuery.DoGuiAction (GuiAction.BtnsOn); 272 | 273 | try 274 | { 275 | semaMoreStop.WaitOne (); 276 | } 277 | finally 278 | { 279 | halt = stop ?? false; 280 | stop = null; 281 | bgwExecuteQuery.DoGuiAction (GuiAction.BtnsOff); 282 | } 283 | } 284 | 285 | 286 | void btnMore_Click (object sender, EventArgs e) 287 | { 288 | stop = false; 289 | semaMoreStop.Set (); 290 | } 291 | 292 | 293 | void btnStop_Click (object sender, EventArgs e) 294 | { 295 | stop = true; 296 | semaMoreStop.Set (); 297 | } 298 | 299 | // click event for (now invisible) Cancel-button, which does not work as expected. 300 | // (execution does not get interrupted, have to sort out why this does not work) 301 | void btnCancelQuery_Click (object sender, EventArgs e) 302 | { 303 | bgwExecuteQuery.CancelAsync (); 304 | btnXeqQuery.Enabled = true; 305 | 306 | while (bgwExecuteQuery.CancellationPending) 307 | { 308 | Application.DoEvents (); 309 | Thread.Sleep (10); 310 | } 311 | } 312 | 313 | 314 | void bgwExecuteQuery_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e) 315 | { 316 | btnCancelQuery.Enabled = false; 317 | btnMore.Enabled = btnStop.Enabled = false; 318 | btnXeqQuery.Enabled = true; 319 | } 320 | 321 | 322 | void bgwExecuteQuery_ProgressChanged (object sender, ProgressChangedEventArgs e) 323 | { 324 | switch ((GuiAction)e.ProgressPercentage) 325 | { 326 | case GuiAction.ReadStart: 327 | tbInput.Text = null; 328 | tbInput.Enabled = true; 329 | btnXeqQuery.Enabled = false; 330 | pnlInput.BackColor = Color.Red; 331 | tbInput.Focus (); 332 | break; 333 | case GuiAction.ReadEnd: 334 | tbInput.Enabled = false; 335 | btnXeqQuery.Enabled = true; 336 | pnlInput.BackColor = tpInterpreter.BackColor; 337 | break; 338 | case GuiAction.ReadLn: 339 | readMode = GuiAction.ReadLn; 340 | break; 341 | case GuiAction.ReadCh: 342 | readMode = GuiAction.ReadCh; 343 | break; 344 | case GuiAction.Write: 345 | tbAnswer.Write (e.UserState as string); 346 | break; 347 | case GuiAction.WriteLn: 348 | tbAnswer.WriteLine (e.UserState as string); 349 | break; 350 | case GuiAction.NewLn: 351 | tbAnswer.WriteLine (); 352 | break; 353 | case GuiAction.Clear: 354 | tbAnswer.Clear (); 355 | break; 356 | case GuiAction.Reset: 357 | tbInput.Clear (); 358 | break; 359 | case GuiAction.BtnsOn: 360 | btnMore.Enabled = btnStop.Enabled = true; 361 | btnXeqQuery.Enabled = false; 362 | lblMoreOrStop.Visible = true; 363 | break; 364 | case GuiAction.BtnsOff: 365 | tbInput.Enabled = false; 366 | btnMore.Enabled = btnStop.Enabled = false; 367 | lblMoreOrStop.Visible = false; 368 | break; 369 | } 370 | } 371 | 372 | 373 | void exitToolStripMenuItem_Click (object sender, EventArgs e) 374 | { 375 | Close (); 376 | } 377 | 378 | 379 | void btnClear_Click (object sender, EventArgs e) 380 | { 381 | rtbQuery.Text = null; 382 | } 383 | 384 | 385 | void btnClose_Click (object sender, EventArgs e) 386 | { 387 | Close (); 388 | } 389 | 390 | 391 | private void tbInput_KeyDown (object sender, KeyEventArgs e) 392 | { 393 | 394 | if (cbNewLines.Checked && e.KeyCode == Keys.Enter) 395 | { 396 | if (readMode == GuiAction.ReadCh) 397 | { 398 | foreach (char c in tbInput.Text) charBuffer.Enqueue (c); 399 | foreach (char c in Environment.NewLine) charBuffer.Enqueue (c); 400 | } 401 | 402 | e.Handled = true; 403 | e.SuppressKeyPress = true; 404 | semaGetInput.Set (); 405 | } 406 | } 407 | 408 | 409 | private void btnEnter_Click (object sender, EventArgs e) 410 | { 411 | if (readMode == GuiAction.ReadCh) 412 | foreach (char c in Environment.NewLine) charBuffer.Enqueue (c); 413 | 414 | semaGetInput.Set (); 415 | } 416 | 417 | 418 | private void cbNewLines_CheckedChanged (object sender, EventArgs e) 419 | { 420 | btnEnter.Visible = (!cbNewLines.Checked); 421 | } 422 | 423 | 424 | private void btnClearA_Click (object sender, EventArgs e) 425 | { 426 | tbAnswer.Clear (); 427 | } 428 | 429 | 430 | //void LoadFileContentsInTextbox (string fileName, RichTextBox rtb) 431 | //{ 432 | // if (File.Exists (fileName)) 433 | // { 434 | // rtb.Text = File.ReadAllText (fileName); 435 | // rtb.Update (); 436 | // rtb.Select (0, 0); 437 | // } 438 | //} 439 | } 440 | 441 | 442 | public static class Extensions 443 | { 444 | static string CRLF = Environment.NewLine; 445 | 446 | public static void Write (this TextBox tb, object s) 447 | { 448 | tb.AppendText (s.ToString ()); 449 | } 450 | 451 | public static void Write (this TextBox tb, string s, params object [] args) 452 | { 453 | tb.AppendText (string.Format (s, args)); 454 | } 455 | 456 | public static void WriteLine (this TextBox tb) 457 | { 458 | tb.AppendText (CRLF); 459 | } 460 | 461 | public static void WriteLine (this TextBox tb, object s) 462 | { 463 | tb.AppendText (s.ToString () + CRLF); 464 | } 465 | 466 | public static void WriteLine (this TextBox tb, string s, params object [] args) 467 | { 468 | if (args.Length == 0) 469 | tb.AppendText (s); 470 | else 471 | tb.AppendText (string.Format (s, args)); 472 | 473 | tb.AppendText (CRLF); 474 | } 475 | 476 | // BackgroundWorker 477 | public static void DoGuiAction (this BackgroundWorker bgw, GuiAction a) 478 | { 479 | bgw.ReportProgress ((int)a, null); 480 | } 481 | 482 | 483 | public static void DoGuiAction (this BackgroundWorker bgw, GuiAction a, string s) 484 | { 485 | bgw.ReportProgress ((int)a, s); 486 | } 487 | } 488 | 489 | } -------------------------------------------------------------------------------- /PLw/PLw.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.21022 7 | 2.0 8 | {BB06ADF9-92C3-4F92-8397-5ACC92208528} 9 | WinExe 10 | Properties 11 | Prolog 12 | PLw 13 | false 14 | true 15 | false 16 | 17 | 18 | 19 | 20 | 3.5 21 | v3.5 22 | C:\Documents and Settings\John.JPO\Desktop\ 23 | true 24 | Disk 25 | false 26 | Foreground 27 | 7 28 | Days 29 | false 30 | false 31 | true 32 | false 33 | 0 34 | 1.0.0.%2a 35 | false 36 | true 37 | LocalIntranet 38 | Properties\app.manifest 39 | 40 | 41 | true 42 | full 43 | false 44 | bin\Debug\ 45 | DEBUG;TRACE 46 | prompt 47 | 4 48 | x86 49 | 50 | 51 | pdbonly 52 | true 53 | bin\Release\ 54 | TRACE 55 | prompt 56 | 4 57 | 58 | 59 | 60 | 61 | 3.5 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | Form 72 | 73 | 74 | MainForm.cs 75 | 76 | 77 | 78 | 79 | Designer 80 | MainForm.cs 81 | 82 | 83 | ResXFileCodeGenerator 84 | Resources.Designer.cs 85 | Designer 86 | 87 | 88 | True 89 | Resources.resx 90 | True 91 | 92 | 93 | 94 | SettingsSingleFileGenerator 95 | Settings.Designer.cs 96 | 97 | 98 | True 99 | Settings.settings 100 | True 101 | 102 | 103 | 104 | 105 | False 106 | .NET Framework 2.0 %28x86%29 107 | true 108 | 109 | 110 | False 111 | .NET Framework 3.0 %28x86%29 112 | false 113 | 114 | 115 | False 116 | .NET Framework 3.5 117 | false 118 | 119 | 120 | 121 | 122 | {6a947b78-96d1-45f2-bb9f-036586bab544} 123 | CSProlog 124 | 125 | 126 | 127 | 134 | -------------------------------------------------------------------------------- /PLw/PLw.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 10.00 2 | # Visual Studio 2008 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PLw", "PLw.csproj", "{BB06ADF9-92C3-4F92-8397-5ACC92208528}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSProlog0", "..\CSProlog0\CSProlog0.csproj", "{FAFEC859-6218-4C55-99EC-5948B5295047}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {BB06ADF9-92C3-4F92-8397-5ACC92208528}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {BB06ADF9-92C3-4F92-8397-5ACC92208528}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {BB06ADF9-92C3-4F92-8397-5ACC92208528}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {BB06ADF9-92C3-4F92-8397-5ACC92208528}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {FAFEC859-6218-4C55-99EC-5948B5295047}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {FAFEC859-6218-4C55-99EC-5948B5295047}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {FAFEC859-6218-4C55-99EC-5948B5295047}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {FAFEC859-6218-4C55-99EC-5948B5295047}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /PLw/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | 5 | namespace Prolog 6 | { 7 | static class Program 8 | { 9 | /// 10 | /// The main entry point for the application. 11 | /// 12 | [STAThread] 13 | static void Main(string[] args) 14 | { 15 | if (args.Length > 0) // batch processing assumed if arguments supplied 16 | { 17 | Prolog.MainForm.BatIO batIO = null; 18 | 19 | try 20 | { 21 | PrologEngine e = new PrologEngine(batIO = new Prolog.MainForm.BatIO()); 22 | e.ProcessArgs(args, true); 23 | Application.Exit(); 24 | 25 | return; 26 | } 27 | finally 28 | { 29 | if (batIO != null) batIO.Close(); 30 | } 31 | } 32 | 33 | Application.EnableVisualStyles(); 34 | Application.SetCompatibleTextRenderingDefault(false); 35 | Application.Run(new MainForm()); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /PLw/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle ("MyNameSpace")] 9 | [assembly: AssemblyDescription ("")] 10 | [assembly: AssemblyConfiguration ("")] 11 | [assembly: AssemblyCompany ("Omnext bv")] 12 | [assembly: AssemblyProduct ("MyNameSpace")] 13 | [assembly: AssemblyCopyright ("Copyright © Omnext bv 2009")] 14 | [assembly: AssemblyTrademark ("")] 15 | [assembly: AssemblyCulture ("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible (false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid ("12ce91b6-4e9a-48a9-a4d2-d30a24cfdf6c")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | [assembly: AssemblyVersion ("1.0.0.0")] 33 | [assembly: AssemblyFileVersion ("1.0.0.0")] 34 | -------------------------------------------------------------------------------- /PLw/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Prolog.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Prolog.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /PLw/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /PLw/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Prolog.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /PLw/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PLw/Properties/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /PLx/PLx.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.21022 7 | 2.0 8 | {E84A59D2-E868-4108-BE9A-55CBB7E85E36} 9 | Exe 10 | Properties 11 | PLx 12 | PLx 13 | v3.5 14 | 512 15 | 16 | 17 | 18 | 19 | 3.5 20 | 21 | 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | x86 30 | 31 | 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | 39 | 40 | 41 | 42 | 3.5 43 | 44 | 45 | 3.5 46 | 47 | 48 | 3.5 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {6a947b78-96d1-45f2-bb9f-036586bab544} 60 | CSProlog 61 | 62 | 63 | 64 | 71 | -------------------------------------------------------------------------------- /PLx/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Prolog; 6 | 7 | /* 8 | * Example of how to use Prolog from within another program. 9 | * 10 | * The PrologEngine class offers two public methods for this purpose: 11 | * - GetAllSolutions 12 | * - GetAllSolutionsXml () 13 | * 14 | * public SolutionSet GetAllSolutions (string sourceFileName, string query, int maxSolutionCount) 15 | * public SolutionSet GetAllSolutions (string sourceFileName, string query) 16 | * 17 | * The purpose of this method is to find all solutions for query 'query', with a maximum number 18 | * of solutions 'maxSolutionCount'. If the value of this parameter is <= 0, all solutions will 19 | * be determined. 20 | * 21 | * 'sourceFileName' may contain the name of a Prolog source file that is to be consulted prior 22 | * to the execution of the query. Enter a null-value if no such source file is present. 23 | * 24 | * The solutions that are found, are collected in an instance of the public 'SolutionSet' class. 25 | * A SolutionSet contains a list of variables of the 'Solution' class type, where each solution 26 | * contains a list of variables of the 'Variable' class type. A Variable contain the name, data type 27 | * and value of the Prolog variable that got instantiated as a result of executing the query. 28 | * 29 | * 'SolutionSet' contains three other properties: 30 | * - string Query : the query you provided as parameter 31 | * - bool Success : true if the query succeeded, false if it did not 32 | * - int Count : the number of Solutions in SolutionSet. Notice that this number may be zero 33 | * also if Success = true, i.e. the query succeeded, but no variables are available 34 | * for output. 35 | * - bool HasError : true if a runtime error occurred. A test on this is left out in the examples 36 | * 1 and 2 below, but this obviously should always be present. 37 | * - string ErrMsg : the text of the error message. 38 | * 39 | * In addition, 'SolutionSet' exports a ToString() method showing the above information. 40 | * 41 | * public string GetAllSolutionsXml (string sourceFileName, string destinFileName, string query, int maxSolutionCount) 42 | * public string GetAllSolutionsXml (string sourceFileName, string destinFileName, string query) 43 | * 44 | * These method are similar to there GetAllSolutions counterparts. The main difference is that 45 | * the solution set is stored in an XML-structure. This structure is written to 'destinFileName' if 46 | * such a name is provided, and returned as method result if 'destinFileName' is null. 47 | * If a runtime error occurs, the text of the error will be stored in a node named . 48 | * 49 | * Result of running the program below: 50 | 51 | Example 1 52 | 53 | Solution 1 54 | P (atom) = peter 55 | N (number) = 7 56 | Solution 2 57 | P (atom) = ann 58 | N (number) = 5 59 | Solution 3 60 | P (atom) = ann 61 | N (number) = 6 62 | Solution 4 63 | P (atom) = pat 64 | N (number) = 8 65 | Solution 5 66 | P (atom) = tom 67 | N (number) = 5 68 | 69 | Example 2 70 | 71 | 72 | 73 | age(P,N) 74 | 75 | peter 76 | 7 77 | 78 | 79 | ann 80 | 5 81 | 82 | 83 | ann 84 | 6 85 | 86 | 87 | pat 88 | 8 89 | 90 | 91 | tom 92 | 5 93 | 94 | 95 | 96 | Example 3 97 | 98 | An error occurred: 99 | *** input string: line 1 position 7 100 | age(P,)))))))))). 101 | *** Unexpected symbol: ")" 102 | *** Expected one of: (, , , , 103 | , , **, /\, <<, /, spy, xor, -, ?=, @>=, @>, >=, >, =\=, =:, ;, : 104 | -, '{}', ^, mod, >>, //, nospy, \/, #, :, =.., @=<, @<, =<, <, =:=, :=, ->, \+, 105 | once, help, =, ==, is, \==, \=, not, , , , [, {, , TRY, {=, =}, , , 107 | 108 | Press any key to exit 109 | */ 110 | 111 | namespace PLx 112 | { 113 | class Program 114 | { 115 | static void Main(string[] args) 116 | { 117 | PrologEngine e = new PrologEngine(); 118 | // Example 1 -- the age/2 predicate is a builtin example; defined in Bootstrap.cs 119 | 120 | Console.WriteLine("Example 1"); 121 | Console.WriteLine(); 122 | 123 | SolutionSet ss = e.GetAllSolutions(null, "age(P,N)"); 124 | 125 | if (ss.Success) 126 | { 127 | for (int i = 0; i < ss.Count; i++) // or: foreach (Solution s in ss.NextSolution) 128 | { 129 | Solution s = ss[i]; 130 | Console.WriteLine("Solution {0}", i + 1); 131 | 132 | foreach (Variable v in s.NextVariable) 133 | Console.WriteLine(string.Format("{0} ({1}) = {2}", v.Name, v.Type, v.Value)); 134 | } 135 | } 136 | else 137 | Console.WriteLine("Failure"); 138 | 139 | // Example 2 -- xml generation 140 | 141 | Console.WriteLine("Example 2"); 142 | Console.WriteLine(); 143 | 144 | string result = e.GetAllSolutionsXml(null, null, "age(P,N)"); 145 | Console.WriteLine(result); 146 | Console.WriteLine(); 147 | 148 | // Example 3 -- error 149 | 150 | Console.WriteLine("Example 3"); 151 | Console.WriteLine(); 152 | 153 | ss = e.GetAllSolutions(null, "age(P,))))))))))"); 154 | 155 | if (ss.HasError) 156 | Console.WriteLine("An error occurred: {0}", ss.ErrMsg); 157 | 158 | Console.WriteLine("Press any key to exit"); 159 | Console.ReadKey(); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /PLx/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle ("PLx")] 9 | [assembly: AssemblyDescription ("")] 10 | [assembly: AssemblyConfiguration ("")] 11 | [assembly: AssemblyCompany ("")] 12 | [assembly: AssemblyProduct ("PLx")] 13 | [assembly: AssemblyCopyright ("Copyright © 2013")] 14 | [assembly: AssemblyTrademark ("")] 15 | [assembly: AssemblyCulture ("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible (false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid ("7702f6aa-1360-4be3-9c4a-8bb6bbc92870")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion ("1.0.0.0")] 36 | [assembly: AssemblyFileVersion ("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /README (2007-2014).doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/README (2007-2014).doc -------------------------------------------------------------------------------- /README (2007-2014).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/CSharpProlog/d30f1bb334b44413f5e338672feffb715bc1ab37/README (2007-2014).pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSharpProlog [![NuGet Package](https://img.shields.io/nuget/v/CSProlog.svg)](https://www.nuget.org/packages/CSProlog/) [![Build status](https://ci.appveyor.com/api/projects/status/prufu2gwyb63l3ua?svg=true)](https://ci.appveyor.com/project/jsakamoto/csharpprolog) 2 | A C# implementation of Prolog 3 | 4 | ```csharp 5 | // PM> Install-Package CSProlog -pre 6 | using System; 7 | using Prolog; 8 | 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | var prolog = new PrologEngine(persistentCommandHistory: false); 14 | 15 | // 'socrates' is human. 16 | prolog.ConsultFromString("human(socrates)."); 17 | // human is bound to die. 18 | prolog.ConsultFromString("mortal(X) :- human(X)."); 19 | 20 | // Question: Shall 'socrates' die? 21 | var solution = prolog.GetFirstSolution(query: "mortal(socrates)."); 22 | Console.WriteLine(solution.Solved); // = "True" (Yes!) 23 | } 24 | } 25 | ``` 26 | ## Installation 27 | 28 | Run the following command from the Visual Studio Package Manager Console to install the latest version: 29 | 30 | `Install-Package CSProlog` 31 | 32 | The NuGet page can be found here:\ 33 | 34 | 35 | ## Solution Layout 36 | ### CSProlog 37 | Prolog Engine 38 | 39 | ### CSProlog.Core.Test 40 | Unit Tests 41 | 42 | ### PL.NETCore 43 | Dotnet Core Console Interactive Interpreter (tested in linux and windows) 44 | 45 | ### PLd 46 | DOS Console Interactive Interpreter 47 | 48 | ### PLw 49 | Windows Forms Example 50 | 51 | ### PLx 52 | An example of how to use the engine within another Program 53 | 54 | 55 | ## For more documents 56 | 57 | Earlier release documents can be found in [README (2007-2014).pdf](README%20(2007-2014).pdf). 58 | 59 | ## Release Notes 60 | 61 | ### v.6.0.0 62 | 63 | - BREAKING CHANGE: Remove "SAMPLES, TESTING & EXPERIMENTAL" predefined predicates. (including CHAT-80 support) 64 | - Fix: "help" predefined predicate dose not work. 65 | - Enhance: GetAllSolutions can work with null file name. 66 | 67 | ### v.5.0.0.1 68 | 69 | - Support: .NET Standard 1.4 (.NET Core) and UWP 70 | 71 | ### v.5.0.0 72 | 73 | - BREAKING CHANGE: Remove dependency of "System.Windows.Forms". 74 | - NuGet package release 75 | 76 | ### Older versions 77 | 78 | Earlier release notes can be found in [README (2007-2014).pdf](README%20(2007-2014).pdf). 79 | 80 | ## License 81 | 82 | [GNU LGPL v.3](LICENSE) 83 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Version 4.1 -- September 2015 2 | 3 | Licensing scheme changed into LGPL. 4 | 5 | Only a few bugfixes (bug in weekno/1/2) and two new predicates (bw_transform/3, combination/3). 6 | 7 | John Pool 8 | Amersfoort 9 | Netherlands 10 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | image: Visual Studio 2019 3 | configuration: Debug 4 | before_build: 5 | - cmd: dotnet restore CSProlog.sln 6 | build: 7 | project: CSProlog.sln 8 | test_script: 9 | - cmd: >- 10 | cd .\CSProlog.Core.Test 11 | 12 | dotnet test --------------------------------------------------------------------------------