/*
 *  SAD / Haigha / main.c -- parses the input and trasfers it to a prover
 *  Copyright (C) 2001-2004  SAD Development Team (see ../README)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

#include "main.h"

static symlist * syms[1022];
symlist * prds = NULL;
symlist * funs = NULL;

ui sym_put(char * str, int kind, int arity)
{
    ui i, S = 1; symlist * l, * m;

    for (i = 0; str[i]; i++)
    { if (str[i] == '#') str[i] = '_'; S = (S*str[i]) % 1021; }

    for (l = syms[S]; l; l = l->next) if (!strcmp(l->str, str))
        if (l->kind == kind && l->arity == arity) return (ui) l;

    addlist(l, syms[S]); l->str = strdup(str);
    l->kind = kind; l->arity = arity;

    if (kind == VS) return (ui) l;
    if (kind == PS) addlist(m, prds); else addlist(m, funs);
    m->str = l->str; m->arity = arity;
    return (ui) l;
}

#define vsym_put(s) sym_put(s, VS, 0)

Term * term_set(ui nm, ui vr)
{
    Term * t = malloc(sizeof(Term));
    t->name = nm; t->vr = vr; t->ch = t->br = NULL; return t;
}

Term * term_dup(Term * t)
{
    Term * s = malloc(sizeof(Term));
    s->ch = t->ch ? term_dup(t->ch) : NULL;
    s->br = t->br ? term_dup(t->br) : NULL;
    s->vr = t->vr; s->name = t->name; return s;
}

void term_out(Term * t)
{
    printf("%s", sym_get(t->name)); if (!t->vr)
    { putchar('('); if (t->ch) term_out(t->ch); putchar(')'); }
    if (t->br) { printf(", "); term_out(t->br); }
}

#define isspec(c)   (c == '(' || c == ')' || c == '?')
#define isconn(c)   (c == '+' || c == '-' || c == ':' || c == '=' || \
                        c == '!' || c == '&' || c == '|' || c == '>' || \
                        c == '~' || c == '@' || c == '$')
#define issymb(c)   (c == '_' || c == '#' || isalnum(c))
#define isvalid(c)  (isspec(c) || issymb(c) || isconn(c))

ui ver_code, fal_code, ann_code, equ_code;
ui neg_code, con_code, dis_code, imp_code;
ui eql_code, uni_code, exi_code, spc_code;

static ui code(char c)
{
    switch (c) {
        case '+' : return ver_code; case '-' : return fal_code;
        case ':' : return ann_code; case '=' : return equ_code;
        case '!' : return neg_code; case '&' : return con_code;
        case '|' : return dis_code; case '>' : return imp_code;
        case '~' : return eql_code; case '@' : return uni_code;
        case '$' : return exi_code; default  : return spc_code; }
}

static int  last;
static char str[128];

static int get_lexem()
{ int i, c;
    do { c = getc(stdin); if (c == EOF) return (last = 0); }
    while (!isvalid(c)); if (!issymb(c)) return (last = c);
    for (i = 0; i < 126 && issymb(c); c = getc(stdin)) str[i++] = c;
    str[i] = '\0'; ungetc(c, stdin); return (last = 'v');
}

static Term * read_formula(int kind)
{
    Term * t; char c = last;

    if (last == 'v') {
        int ar; char * s = strdup(str); Term * tc = NULL;
        get_lexem(); t = term_set(0, 1); if (last != '(')
        {   t->name = vsym_put(s); free(s); return t; }
        get_lexem(); for (ar = 0; last != ')'; ar++)
            if (tc) tc = tc->br = read_formula(FS);
            else    tc = t->ch  = read_formula(FS);
        t->name = sym_put(s, kind, ar); t->vr = 0; free(s);
        get_lexem(); return t;
    }

    t = term_set(code(c), 0); get_lexem();
    switch (c) {
        case '+' : case '-' : break;
        case '@' : case '$' : case ':' :
                    ARG1(t) = term_set(vsym_put(str), 1);
                    get_lexem(); ARG2(t) = read_formula(PS); break;
        case '=' :  ARG1(t) = read_formula(FS);
                    ARG2(t) = read_formula(FS); break;
        default  :  ARG1(t) = read_formula(PS); if (c == '!') break;
                    ARG2(t) = read_formula(PS);
    }
    return t;
}

/*
 *  The other Messenger's called Hatta. I must have two,
 *  you know -- to come and go. One to come, and one to go.
 */

int main(int argc, char** argv)
{
    Formula * f, * fl = NULL; ui time;

    if (argc < 3)
    {
        fprintf(stderr, "Usage: haigha <prover> <path to prover> <options>\n\n");
        fprintf(stderr, "Provers available: spass\n");
        return 1;
    }

    ver_code = vsym_put("+"); fal_code = vsym_put("-"); ann_code = vsym_put(":");
    equ_code = vsym_put("="); neg_code = vsym_put("!"); con_code = vsym_put("&");
    dis_code = vsym_put("|"); imp_code = vsym_put(">"); eql_code = vsym_put("~");
    uni_code = vsym_put("@"); exi_code = vsym_put("$"); spc_code = vsym_put("_");

    get_lexem(); while (last != '?')
    {
        addlist(f, fl); f->mark = strdup(str);
        get_lexem(); f->fterm = read_formula(PS);
    }
    addlist(f, fl); f->mark = "#";
    get_lexem(); f->fterm = read_formula(PS);
    time  = atoi(str); if (time < 1) time = 180;

    if (!strcmp(argv[1], "spass")) spass_call(argc - 2, argv + 2, fl, time);
    else
    {
        fprintf(stderr, "Usage: haigha <prover> <path to prover> <prover args>\n\n");
        fprintf(stderr, "Provers available: spass\n");
        return 1;
    }

    return 0;
}
