/****************************************************************************** UNSW Prolog (version 4) Written by Claude Sammut Department of Computer Science University of New South Wales (and St. Joseph's U., Philadelphia) Copyright (c) 1983 - Claude Sammut ******************************************************************************/ #include #include #include "g.h" #include "in.h" /* Token variables. Instantiated in lex.c */ extern int linen; extern char interpret; extern char *cur_file; extern int library; /* constant atoms used as parameters in the parser. Initialized in pred.c */ extern atom *_comma, *_dot, *_lpren, *_cut, *nil, *_prefix, *_infix, *_postfix, *_rpren, *_lbrac, *_rbrac, *_query, *_uplus, *_uminus, *_eof, *_neck, *_dot_dot, *_question, *_command, *_bang, *_bar, *_lbrace, *_rbrace; static atom dummy = {ATOM, FX, 999, 0, 0, "", 0, 0}; /* memory mangement functions defined in mem.c */ extern pval new(); extern compterm *record(); extern int execute(); extern atom *add_clause(), *nonop(); extern pval in_uniop(), in_biop(); /* lexical analysis routine declared in lex.c */ extern pval getatom(); extern ungetatom(); /* global flags and counters that are used outside this file */ int argn = 0, p_read_on = FALSE; /* error flag and error recovery buffers */ int read_err = FALSE, load_err = FALSE; jmp_buf env1, env2; /* SYNTAX ANALYSIS ROUTINES */ error(msg, skip) char *msg; int skip; { extern atom *prompt_string, *init_prompt; extern linen, pushed_back; load_err = read_err = TRUE; p_read_on = FALSE; pushed_back = -1; prompt_string = init_prompt; if (interpret) { fprintf(stderr, "SYNTAX ERROR: %s\n", msg); if (skip) { while (readch != '\n'); prompt(); } } else { fprintf(stderr, "%s: line %d: %s\n", cur_file, linen, msg); if (skip) while (readch != '.'); } longjmp(env2,1); } pval scan() { pval rval; rval = getatom(); if (feof(input) && ! p_read_on) { fprintf(stderr, "EOF unexpected\n"); longjmp(env1,1); } return(rval); } isvar(string) char *string; { register char c = *string; return((c >= 'A' && c <= 'Z') || c == '_'); } prefix(a) atom **a; { register atom *p; for (p = *a; p && strcmp(NAME(*a), NAME(p)) == 0; p = p -> link) { if (p -> op_t == FX || p -> op_t == FY) { *a = p; return(TRUE); } } return(FALSE); } infix(a) atom **a; { register atom *p; for (p = *a; p && strcmp(NAME(*a), NAME(p)) == 0; p = p -> link) if (p -> op_t == XFX || p -> op_t == XFY || p -> op_t == YFX) { *a = p; return(TRUE); } return(FALSE); } postfix(a) atom **a; { register atom *p; for (p = *a; p && strcmp(NAME(*a), NAME(p)) == 0; p = p -> link) if (p -> op_t == XF || p -> op_t == YF) { *a = p; return(TRUE); } return(FALSE); } static moreimportant(op1,op2) atom *op1,*op2; { if (strcmp(op1 -> name, op2 -> name) == 0) return(op1 -> op_t == XFY); else return(op1 -> pred < op2 -> pred); } static pval in_list() { extern pval expression(); pval p, expr, rval; p = scan(); if (p == (pval) _rbrac) return((pval) nil); else ungetatom(p); expr = expression(&dummy); p = scan(); if (p == (pval) _comma) { p = scan(); if (p == (pval) _dot_dot) { rval = new(LIST); rval -> c.term[0] = expr; rval -> c.term[1] = expression(&dummy); if (scan() != (pval) _rbrac) error("malformed list end", TRUE); return(rval); } else ungetatom(p); rval = new(LIST); rval -> c.term[0] = expr; rval -> c.term[1] = in_list(); } else if (p == (pval) _bar) { rval = new(LIST); rval -> c.term[0] = expr; rval -> c.term[1] = expression(&dummy); if (scan() != (pval) _rbrac) error("malformed list end", TRUE); return(rval); } else if (p == (pval) _rbrac) { rval = new(LIST); rval -> c.term[0] = expr; rval -> c.term[1] = (pval) nil; } else error("malformed list", TRUE); return(rval); } static pval expr_list(nterms) char nterms; { extern pval expression(); pval expr, rval; expr = expression(&dummy); rval = scan(); if (rval == (pval) _comma) { rval = expr_list(++nterms); rval -> c.term[nterms--] = expr; } else if (rval == (pval) _rpren) { rval = (pval) record(++nterms); rval -> c.term[nterms--] = expr; } else error(", not found", TRUE); return(rval); } pval expression(given) pval given; { extern pval expr_list(); register i; pval rval, p; rval = scan(); if (isinteger(rval)) goto OPERATOR; if (TYPE(rval) == STRING) goto FUNCTION; if (rval == (pval) _lbrac) { rval = in_list(); goto OPERATOR; } if (rval == (pval) _lpren) { rval = expression(_rpren); if (scan() == (pval) _rpren) goto OPERATOR; else error(" missing )", TRUE); } if (rval == (pval) _lbrace) { rval = expression(_rbrace); if (scan() == (pval) _rbrace) { p = (pval) record(1); p -> c.term[0] = (pval) _lbrace; p -> c.term[1] = rval; rval = p; goto OPERATOR; } else error(" missing }", TRUE); } if (isvar(NAME(rval))) #ifdef PRINC_VAR goto FUNCTION; #else goto OPERATOR; #endif if (! prefix(&rval) || ungetc(getc(input), input) == '(') { rval = (pval) nonop(rval); goto FUNCTION; } p = scan(); if (isatom(p) && p -> a.pred > 1200) { ungetatom(p); return((pval) nonop(rval)); } if (rval == (pval) _uplus) { if (isinteger(p)) { rval = p; goto OPERATOR; } ungetatom(p); rval = in_uniop(rval, expression(rval)); } else if (rval == (pval) _uminus) { if (isinteger(p)) { p -> i.int_val = -(p -> i.int_val); rval = p; goto OPERATOR; } ungetatom(p); rval = in_uniop(rval, expression(rval)); } else if (rval == (pval) _prefix) { if (prefix(&p)) rval = p; else ungetatom(p); } else if (rval == (pval) _infix) { if (infix(&p)) rval = p; else ungetatom(p); } else if (rval == (pval) _postfix) { if (postfix(&p)) rval = p; else ungetatom(p); } else { ungetatom(p); rval = in_uniop(rval, expression(rval)); } FUNCTION: p = scan(); if (p == (pval) _lpren) { p = (pval) expr_list(0); p -> c.term[0] = rval; rval = p; } else ungetatom(p); OPERATOR: repeat { p = scan(); if (TYPE(p) != ATOM && TYPE(p) != PREDEF) { ungetatom(p); return(rval); } if (postfix(&p) && moreimportant(p, given)) { rval = in_uniop(p, rval); if (p -> a.pred >= 1200) return(rval); } else if (infix(&p) && moreimportant(p, given)) rval = in_biop(p, rval, expression(p)); else { ungetatom(p); return(rval); } } } pval append1(l, a) pval l; atom *a; { register pval p = l; if (p == (pval) nil) { p = new(LIST); p -> c.term[0] = (pval) a; p -> c.term[1] = (pval) nil; return(p); } else { repeat { if (p -> c.term[0] == (pval) a) return(l); if (p -> c.term[1] == (pval) nil) break; p = p -> c.term[1]; } p -> c.term[1] = new(LIST); p = p -> c.term[1]; p -> c.term[0] = (pval) a; p -> c.term[1] = (pval) nil; return(l); } } static do_command(expr, ifquery) pval expr; { extern pval mkbody(); pval cl; cl = mkbody(expr, 0, 1); execute(((clause *) cl), argn, ifquery); free_term(cl); } pval proc_list; static p_assert(expr) pval expr; { extern int library; extern pval mkclause(); register pval rval; atom *a; rval = mkclause(expr, 0); rval -> g.nvars = argn; a = add_clause(rval); if (! (interpret || library)) proc_list = append1(proc_list, a); argn = 0; } #define principal(x) expr -> c.term[0] == (pval) x static parse() { extern var **varcell; pval expr; var **old_vc, *vc[MAXVAR]; argn = 0; old_vc = varcell; varcell = vc; read_err = FALSE; expr = expression(_rpren); if (principal(_bang)) do_command(expr -> c.term[1], FALSE); else if (principal(_question)) do_command(expr -> c.term[1], TRUE); else if (principal(_dot)) { expr = expr -> c.term[1]; if (principal(_command)) do_command(expr -> c.term[1], FALSE); else if (principal(_query)) do_command(expr -> c.term[1], TRUE); else p_assert(expr); } else { free_term(expr); error("Input must be a question, command or assertion",TRUE); } free_term(expr); varcell = old_vc; argn = 0; } evloop() { extern FILE *input; load_err = FALSE; if (interpret) prompt(); repeat if (! setjmp(env1)) { if (setjmp(env2)) /* syntax error and abort returns here */; skipd(); if (feof(input)) break; parse(); fflush(stdout); } } pval inchar() { extern pval intern(); extern FILE *input; char buf[2]; buf[0] = (char) readch; if (feof(input)) return((pval) _eof); buf[1] = 0; return(intern(ATOM, buf, 2, FALSE)); }