/* Copyright (c) 1982 Regents of the University of California */

static char sccsid[] = "@(#)keywords.c 1.3 5/18/83";

/*
 * Keyword management.
 */

#include "defs.h"
#include "keywords.h"
#include "scanner.h"
#include "names.h"
#include "symbols.h"
#include "tree.h"
#include "y.tab.h"

#ifndef public
#include "scanner.h"
#endif

private String reserved[] ={
    "alias", "and", "assign", "at", "call", "catch", "cont",
    "debug", "delete", "div", "dump", "edit", "file", "func",
    "gripe", "help", "if", "ignore", "in",
    "list", "mod", "next", "nexti", "nil", "not", "or",
    "print", "psym", "quit", "run",
    "sh", "skip", "source", "status", "step", "stepi",
    "stop", "stopi", "trace", "tracei",
    "use", "whatis", "when", "where", "whereis", "which",
    "INT", "REAL", "NAME", "STRING",
    "LFORMER", "RFORMER", "#^", "->"
};

/*
 * The keyword table is a traditional hash table with collisions
 * resolved by chaining.
 */

#define HASHTABLESIZE 503

typedef struct Keyword {
    Name name;
    Token toknum : 16;
    Boolean isalias : 16;
    struct Keyword *chain;
} *Keyword;

typedef unsigned int Hashvalue;

private Keyword hashtab[HASHTABLESIZE];

#define hash(n) ((((unsigned) n) >> 2) mod HASHTABLESIZE)

/*
 * Enter all the reserved words into the keyword table.
 */

public enterkeywords()
{
    register Integer i;

    for (i = ALIAS; i <= WHICH; i++) {
	keyword(reserved[ord(i) - ord(ALIAS)], i, false);
    }
    keyword("set", ASSIGN, false);
}

/*
 * Deallocate the keyword table.
 */

public keywords_free()
{
    register Integer i;
    register Keyword k, nextk;

    for (i = 0; i < HASHTABLESIZE; i++) {
	k = hashtab[i];
	while (k != nil) {
	    nextk = k->chain;
	    dispose(k);
	    k = nextk;
	}
	hashtab[i] = nil;
    }
}

/*
 * Enter a keyword into the name table.  It is assumed to not be there already.
 * The string is assumed to be statically allocated.
 */

private keyword(s, t, isalias)
String s;
Token t;
Boolean isalias;
{
    register Hashvalue h;
    register Keyword k;
    Name n;

    n = identname(s, true);
    h = hash(n);
    k = new(Keyword);
    k->name = n;
    k->toknum = t;
    k->isalias = isalias;
    k->chain = hashtab[h];
    hashtab[h] = k;
}

/*
 * Return the string associated with a token corresponding to a keyword.
 */

public String keywdstring(t)
Token t;
{
    return reserved[ord(t) - ord(ALIAS)];
}

/*
 * Find a keyword in the keyword table.
 * We assume that tokens cannot legitimately be nil (0).
 */

public Token findkeyword(n)
Name n;
{
    register Hashvalue h;
    register Keyword k;
    Token t;

    h = hash(n);
    k = hashtab[h];
    while (k != nil and k->name != n) {
	k = k->chain;
    }
    if (k == nil) {
	t = nil;
    } else {
	t = k->toknum;
    }
    return t;
}

/*
 * Create an alias.
 */

public enter_alias(newcmd, oldcmd)
Name newcmd;
Name oldcmd;
{
    Token t;

    t = findkeyword(oldcmd);
    if (t == nil) {
	error("\"%s\" is not a command", ident(oldcmd));
    } else {
	keyword(ident(newcmd), t, true);
    }
}

/*
 * Print out an alias.
 */

public print_alias(cmd)
Name cmd;
{
    register Keyword k;
    register Integer i;
    Token t;

    if (cmd == nil) {
	for (i = 0; i < HASHTABLESIZE; i++) {
	    for (k = hashtab[i]; k != nil; k = k->chain) {
		if (k->isalias) {
		    if (isredirected()) {
			printf("alias ");
		    }
		    printf("%s\t%s\n", ident(k->name), keywdstring(k->toknum));
		}
	    }
	}
    } else {
	t = findkeyword(cmd);
	if (t == nil) {
	    printf("\n");
	} else {
	    printf("%s\n", keywdstring(t));
	}
    }
}
