将sw - prolog连接到c++的问题

Problems interfacing SWI-Prolog to C++

本文关键字:c++ 问题 连接 sw prolog      更新时间:2023-10-16

我在绞尽脑汁试图使sw - prolog与c++玩得很好。现在,在我开始解释我的问题是什么之前,我想首先说明我的项目是什么,以及我选择了什么工具来开发解决方案。

我的教授给我的任务是开发一个GUI程序作为SWI-prolog的前端,这个前端是用c++开发的。我选择使用Qt来设计GUI,并使用c++作为后端来桥接sw - prolog到应用程序。这个应用程序的用户应该能够输入一些列表,然后通过prolog选择要应用于它们的操作,例如,如果我输入一个数字列表,那么通过单击一个按钮,用户将获得该列表中所有成对数字的另一个列表(如果有的话)。我正在unix操作系统上开发,更具体地说,是基于archlinux和manjaro的netrunner滚动发行版。

我做了一些研究,似乎最好的行动方案是为了接口SWI-Prolog(我也可以提到,我的教授也建议这样做),是使用Volker Wysk开发的头文件和源文件;作为参考,这里是包含这些文件的压缩文件的链接http://www.volker-wysk.de/swiprolog-c++/index.html

现在这是我的问题:如果你访问了我刚刚给你的页面,你会发现这个c++实现的SWI-Prolog接口是相当旧的:最后一次工作是在2002年。我不得不修改头文件,这样我就可以摆脱一些错误,就像将使用名称空间性病或改变# # include ostream.h包括上ostream,所以我设法让错误数到只有两个,我不能设法解决,我想我不能,因为有两个函数的实现在任何地方我找不到:声明的函数,但它应该运行的代码当他们被称为不能被发现。

我现在将列出我认为最相关的文件内容。我已经安装了最新版本的wi - prolog,因此wi - prolog .h头文件是安装最新prolog(版本6.6.5)时附带的最新头文件。

#-------------------------------------------------
#
# Project created by QtCreator 2014-07-05T12:38:45
#
#-------------------------------------------------
QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = prologFrontend
TEMPLATE = app

SOURCES += main.cpp
        mainwindow.cpp 
    ../../../../../../../../usr/local/share/swiprolog-c++/prolog.cpp
LIBS += -L/usr/lib/swipl-6.6.5/lib/x86_64-linux -lswipl
HEADERS  += mainwindow.h
FORMS    += mainwindow.ui

prologFrontend的内容。

#include "mainwindow.h"
#include <QApplication>
#include <prolog.hpp>

int main(int argc, char *argv[])
{
    try {
        Prolog_impl::prolog_init(argc, argv);
    } catch(Prolog_impl::PlError &error) {
    }

    QApplication prog(argc, argv);
    MainWindow w;
    w.show();
    return prog.exec();
}

main.cpp文件的内容

我会复制Volker Wysk制作的头文件和源文件的全部内容,但它太长了,无法在这里容纳。如果你从我已经发布的他的网站的链接中下载的话,你可以看看他们。接下来是我得到的错误和两个相应的代码片段,它们发生在他所做的.cpp文件中:

// part of SWI-Prolog, but not exportet by header file
// /usr/local/src/swiprolog-4.0.9/src/pl-funcs.h
//NOTE: this function is declared here but it's even not to be found in the header file
//prolog.hpp. Its implementation can't be found anywhere using the function definition
//navigation capability of Qt so, basically, its a function that does nothing.
extern "C"{
unsigned long pl_atom_to_term(term_t in_atom,
                              term_t out_term,
                              term_t out_bindings);
}
bool Prolog_impl::atom_to_term(const char* text, Term* t, list<Term::Binding>* b)
{
  Term in_atom = Atom(text);
  Term out_term;
  Term out_bindings;
  if (!pl_atom_to_term(in_atom.lsi, out_term.lsi, out_bindings.lsi))
    return false;
  if (t) *t = out_term;
  if (b) *b = out_bindings;
  return true;
}
/usr/local/share/swiprolog-c++/prolog.cpp:45: error: undefined reference to ' pl_atom_to_term'.
//Note that this code has the same issues as the one above: no implementation to be found
extern "C"{
unsigned long pl_copy_term(term_t in, term_t out);
}
Term Prolog_impl::copy_term(Term t)
{
  term_t t2 = PL_new_term_ref();
  if (!pl_copy_term(t.lsi, t2))
    throw LogicError("copy_term(Term)", "failure calling pl_copy_term()");
  return Term(t2);
}
/usr/local/share/swiprolog-c++/prolog.cpp:60: error: undefined reference to ' pl_copy_term'.

除了我必须对我已经提到的头文件进行的更改之外,我还必须修复头文件中的这行代码:

#include <SWI-Prolog.h>

:

#include "/usr/lib/swipl-6.6.5/include/SWI-Prolog.h"

这是因为,否则,编译器会抱怨找不到头文件。

我的猜测是这些函数曾经存在于较旧的SWI-Prolog版本中。关于如何处理这个任务,我没有真正的线索,我试着阅读使用volker的实现的其他替代方案,但就像在网上几乎没有关于如何将Prolog与c++接口的好信息。

非常感谢您花时间阅读我的问题。如果你有一个有效的解决方案,请告诉我。它不一定是SWI-Prolog,它可以是任何其他与c++接口良好的Prolog环境,并且使用或多或少与SWI-Prolog使用相同的语法,尽管我认为语法已经是所有环境的标准。

Package swil -win是一个工作的SWI-Prolog/Qt接口,可移植到Linux,MacOS,Windows上。我在这里有很多其他的,但它们现在仅限于在Linux上运行…

我想知道为什么,除了Qt特定的问题,你选择了一个旧的,没有维护的c++接口,当这里有一个"官方"的。这个接口工作得很好,提供了基于异常处理和自动类型转换的参数验证。然后很容易添加到接口中—例如,从PREDICATE.h

typedef PlTerm T;
#define LOOP__ { } operator bool() { return next_solution(); }
#define query0(P) struct P : PlQuery { P() : PlQuery(#P, V()) LOOP__ };
#define query1(P) struct P : PlQuery { P(T A) : PlQuery(#P, V(A)) LOOP__ };
...

允许
query1(current_predicate)
void Completion::initialize(QSet<QString> &strings, bool reload) {
    Q_UNUSED(reload)
    T PRED;
    for (current_predicate cp(PRED); cp; ) {
        QString p = t2w(PRED);
        if (p[0].isLetter())
            strings.insert(p);
    }
    qDebug() << "Completion::initialize loaded" << strings.count();
}

关于你的具体问题,可能那些函数已经过时了,你应该坚持使用这里记录的C Api(也称为外语接口)

查看swiprolog-c++-0.1.0Makefile,看起来需要使用一个特殊的链接器,称为plld。因此,您需要使用常用的编译器来生成目标文件,然后使用该链接器来创建可执行文件。

生成文件中的plld行如下所示:

main : main.o prolog.o test.pl
    plld -o $@ -ld $(CC) $^ -lstdc++

"recipe"行展开为:

plld -o main -ld gcc main.o prolog.o test.pl -lstdc++