#include <SWI-Prolog.h>
#include <iostream>
#include <string>
#include <vector>
#include <cctype>
// Global array to store detected variables
std::vector<std::string> detected_variables;
// Function to analyze and detect variables in a query
int process_query(const std::string &query) {
detected_variables.clear(); // Reset the detected variables
std::string current_term; // Store the current term
bool after_equals = false; // Indicates if we're after an '=' sign
for (size_t i = 0; i < query.size(); ++i) {
char c = query[i];
// Stop processing if a period ('.') is reached
if (c == '.') {
// Check the last term before exiting
if (after_equals && !current_term.empty() && (isupper(current_term[0]) || current_term[0] == '_')) {
detected_variables.push_back(current_term);
std::cout << "Detected variable 1: " << current_term << std::endl;
}
break;
}
// Detect the '=' sign
if (c == '=') {
after_equals = true; // Switch to the right-hand side of the equality
current_term.clear(); // Reset for the next term
continue;
}
// Detect separators
if (c == ',' || c == '[' || c == ']' || c == '(' || c == ')' || c == ' ') {
if (!current_term.empty()) {
// Check if the term starts with an uppercase letter or underscore and if we're after '='
if (after_equals && (isupper(current_term[0]) || current_term[0] == '_')) {
detected_variables.push_back(current_term);
std::cout << "Detected variable 2: " << current_term << std::endl;
}
current_term.clear(); // Reset for the next term
}
continue;
}
// Append the character to the current term
current_term += c;
}
return detected_variables.size();
}
// Function to display a Prolog list
void display_list(term_t list) {
term_t head = PL_new_term_ref();
term_t tail = PL_copy_term_ref(list);
std::cout << "[";
bool first = true;
while (PL_get_list(tail, head, tail)) {
if (!first) std::cout << ", ";
first = false;
char *element = nullptr;
if (PL_get_chars(head, &element, CVT_WRITE | BUF_DISCARDABLE)) {
std::cout << element;
} else {
std::cerr << "Error: Unable to extract an element from the list.\n";
}
}
if (!PL_get_nil(tail)) {
std::cerr << "Error: The term is not a well-formed list.\n";
}
std::cout << "]";
}
// Function to extract a list from a complex term or its subpart
bool extract_list(term_t term, const std::string &label) {
term_t sub_term = PL_new_term_ref();
// Check if the term is an equality functor (=) with two arguments
if (PL_is_functor(term, PL_new_functor(PL_new_atom("="), 2))) {
if (PL_get_arg(2, term, sub_term) && PL_is_list(sub_term)) {
std::cout << label << " = ";
display_list(sub_term);
std::cout << std::endl;
return true;
}
} else if (PL_is_list(term)) { // If the term is directly a list
std::cout << label << " = ";
display_list(term);
std::cout << std::endl;
return true;
} else if (PL_is_functor(term, PL_new_functor(PL_new_atom("situation_facts"), 6))) {
// Attempt to extract the 6th part for Facts
if (PL_get_arg(6, term, sub_term) && PL_is_list(sub_term)) {
std::cout << label << " = ";
display_list(sub_term);
std::cout << std::endl;
return true;
}
}
// On failure, display raw content for diagnostics
char *term_str = nullptr;
if (PL_get_chars(term, &term_str, CVT_WRITE | BUF_DISCARDABLE)) {
std::cerr << label << " raw content: " << term_str << std::endl;
} else {
std::cerr << "Error: Unable to extract " << label << ".\n";
}
return false;
}
// Process and display solutions
void process_solution(term_t goal) {
for (size_t i = 0; i < detected_variables.size(); ++i) {
const std::string &variable_name = detected_variables[i];
term_t variable_term = PL_new_term_ref();
// Retrieve the argument corresponding to the variable
if (PL_get_arg(static_cast<int>(i + 1), goal, variable_term)) {
if (!extract_list(variable_term, variable_name)) {
std::cerr << "Error: " << variable_name << " not readable or not formatted as a list.\n";
}
} else {
std::cerr << "Error: Unable to extract " << variable_name << ".\n";
}
}
}
// Execute a user query
void execute_query(const std::string &query) {
term_t goal = PL_new_term_ref();
if (!PL_chars_to_term(query.c_str(), goal)) {
std::cerr << "Error: Invalid input. Query ignored.\n";
return;
}
predicate_t call_predicate = PL_predicate("call", 1, NULL);
term_t args = PL_new_term_refs(1);
PL_put_term(args, goal);
qid_t query_id = PL_open_query(NULL, PL_Q_NORMAL, call_predicate, args);
if (!query_id) {
std::cerr << "Error: Unable to open the query.\n";
return;
}
bool solution_found = false;
while (PL_next_solution(query_id)) {
solution_found = true;
process_solution(goal); // Process the solution
}
if (!solution_found) {
std::cout << "false." << std::endl; // Display false if no solution
} else {
std::cout << "false." << std::endl; // End with false after solutions
}
PL_close_query(query_id);
}
int main(int argc, char **argv) {
if (!PL_initialise(argc, argv)) {
std::cerr << "Error: Unable to initialize SWI-Prolog.\n";
return 1;
}
const char *prolog_file = "/home/frank/DARBS/testeur_pro/src/helper_rulesx1.pl";
term_t consult_term = PL_new_term_ref();
std::string consult_command = "consult('" + std::string(prolog_file) + "').";
if (!PL_chars_to_term(consult_command.c_str(), consult_term) || !PL_call(consult_term, NULL)) {
std::cerr << "Error: Unable to load the Prolog file: " << prolog_file << "\n";
PL_halt(1);
return 1;
}
std::cout << "Prolog file loaded successfully.\n";
std::string input;
while (true) {
std::cout << "Enter a Prolog query (or 'quit' to exit): ";
std::getline(std::cin, input);
if (input == "quit") break;
process_query(input); // Dynamically store detected variables
execute_query(input);
}
PL_halt(0);
return 0;
}
i would like to have the result of my execution in a variable and print it.
Thanks
I don’t understand what you want to do here (and don’t have time to read through your code) … please be a bit more specific.
Your code doesn’t use the C++ API at all as far as I can tell. In general, the C++ API is quite a bit easier and less error-prone than the C API. If you want to use the C API, I suggest using the Plx_
versions of the functions.
Anyway, if you look in test_cpp.cpp, the following predicates (and how they’re called in test_cpp.pl) might help you:
call_cp_ex
can_unify
record_ext
Also, with_output_to/2 might be of use (e.g. with_output_to(string(Astr), write(current_output, A))
.