swig/Source/Swig/tree.c
Dave Beazley 300da52da5 Fixed minor const problem
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@960 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2000-12-18 03:07:47 +00:00

513 lines
14 KiB
C

/* -----------------------------------------------------------------------------
* tree.c
*
* This file provides some general purpose functions for manipulating
* parse trees.
*
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
*
* Copyright (C) 1999-2000. The University of Chicago
* See the file LICENSE for information on usage and redistribution.
* ----------------------------------------------------------------------------- */
#include "swig.h"
static char cvsroot[] = "$Header$";
/* Hash table mapping tag names to handler functions */
static Hash *rules = 0;
static int debug_emit = 0;
/* -----------------------------------------------------------------------------
* Swig_next()
* Swig_prev()
*
* Return next/prev node in a parse tree
* ----------------------------------------------------------------------------- */
DOH *Swig_next(DOH *obj) {
return Getnext(obj);
}
DOH *Swig_prev(DOH *obj) {
return Getprev(obj);
}
void Swig_debug_emit(int n) {
debug_emit = n;
}
/* -----------------------------------------------------------------------------
* Swig_dump_tags()
*
* Dump the tag structure of a parse tree to standard output
* ----------------------------------------------------------------------------- */
void
Swig_dump_tags(DOH *obj, DOH *root) {
DOH *croot, *newroot;
DOH *cobj;
if (!root) croot = NewString("");
else croot = root;
while (obj) {
Printf(stdout,"%s . %s (%s:%d)\n", croot, Getattr(obj,"tag"), Getfile(obj), Getline(obj));
cobj = Getattr(obj,"child");
if (cobj) {
newroot = NewStringf("%s . %s",croot,Getattr(obj,"tag"));
Swig_dump_tags(cobj,newroot);
Delete(newroot);
}
obj = Swig_next(obj);
}
if (!root)
Delete(croot);
}
/* -----------------------------------------------------------------------------
* Swig_dump_tree()
*
* Dump the tree structure of a parse tree to standard output
* ----------------------------------------------------------------------------- */
static int indent_level = 0;
static void print_indent(int l) {
int i;
for (i = 0; i < indent_level; i++) {
fputc(' ', stdout);
}
if (l) {
fputc('|', stdout);
fputc(' ', stdout);
}
}
void
Swig_dump_tree(DOH *obj) {
DOH *k;
DOH *cobj;
while (obj) {
print_indent(0);
Printf(stdout,"+++ %s ----------------------------------------\n", Getattr(obj,"tag"));
k = Firstkey(obj);
while (k) {
if ((Cmp(k,"tag") == 0) || (Cmp(k,"child") == 0) ||
(Cmp(k,"parent") == 0) || (Cmp(k,"next") == 0) ||
(Cmp(k,"prev") == 0)) {
/* Do nothing */
} else if (Cmp(k,"parms") == 0) {
print_indent(2);
Printf(stdout,"%-12s - %s\n", k, ParmList_protostr(Getattr(obj,k)));
} else {
DOH *o;
char *trunc = "";
print_indent(2);
o = Str(Getattr(obj,k));
if (Len(o) > 40) {
trunc = "...";
}
Printf(stdout,"%-12s - \"%(escape)-0.40s%s\"\n", k, o, trunc);
Delete(o);
}
k = Nextkey(obj);
}
cobj = Getattr(obj,"child");
if (cobj) {
indent_level += 6;
Printf(stdout,"\n");
Swig_dump_tree(cobj);
indent_level -= 6;
} else {
print_indent(1);
Printf(stdout,"\n");
}
obj = Swig_next(obj);
}
}
/* -----------------------------------------------------------------------------
* Swig_add_rule()
*
* Adds a new rule to the tree walking code.
* ----------------------------------------------------------------------------- */
void
Swig_add_rule(const String_or_char *name, int (*action)(DOH *node, void *clientdata))
{
if (!rules) rules = NewHash();
if (action)
Setattr(rules,name,NewVoid((void *) action,0));
else
Delattr(rules,name);
if (debug_emit) {
Printf(stderr,"Swig_add_rule : '%s' -> %x\n", name, action);
}
}
/* -----------------------------------------------------------------------------
* Swig_add_rules()
*
* Add a complete set of rules to the rule system
* ----------------------------------------------------------------------------- */
void
Swig_add_rules(SwigRule ruleset[]) {
int i = 0;
while (ruleset[i].name) {
Swig_add_rule(ruleset[i].name, ruleset[i].action);
i++;
}
}
/* -----------------------------------------------------------------------------
* Swig_clear_rules()
*
* Clears all of the existing rules
* ----------------------------------------------------------------------------- */
void
Swig_clear_rules()
{
if (rules) Delete(rules);
rules = NewHash();
if (debug_emit) {
Printf(stderr,"Swig_clear_rules :\n");
}
}
/* -----------------------------------------------------------------------------
* Swig_dump_rules()
*
* Print out debugging information for the rules
* ----------------------------------------------------------------------------- */
void
Swig_dump_rules() {
String *key;
Printf(stdout,"SWIG emit rules:::\n");
if (!rules) {
Printf(stdout," No rules defined.\n");
return;
}
key = Firstkey(rules);
while (key) {
Printf(stdout," '%-15s' -> %x\n", key, GetVoid(rules,key));
key = Nextkey(rules);
}
}
/* -----------------------------------------------------------------------------
* Swig_tag_check()
*
* Checks the tag name of an object taking into account namespace issues.
* For example, a check of "function" will match any object with a tag
* of the form "xxx:function" whereas a check of "c:function" will check
* for a more exact match. Returns 1 if a match is found, 0 otherwise
* ----------------------------------------------------------------------------- */
int
Swig_tag_check(DOH *obj, const String_or_char *tagname) {
String *tag;
char *tc;
char *tnc;
tag = Getattr(obj,"tag");
assert(tag);
tnc = Char(tag);
tc = Char(tagname);
while (tnc) {
if (strcmp(tc,tnc) == 0) return 1;
tnc = strchr(tnc,':');
if (tnc) tnc++;
}
return 0;
}
/* -----------------------------------------------------------------------------
* Swig_set_callback()
*
* Sets a parser callback function for a node.
* ----------------------------------------------------------------------------- */
void
Swig_set_callback(DOH *obj, void (*cb)(void *clientdata), void *clientdata) {
SetVoid(obj,"-callback-",(void *)cb);
if (clientdata)
SetVoid(obj,"-callbackarg-", clientdata);
}
/* -----------------------------------------------------------------------------
* Swig_set_trace()
*
* Sets a tracing function on a parse tree node. Returns the old tracing
* function (if any).
* ----------------------------------------------------------------------------- */
void (*Swig_set_trace(DOH *obj, void (*cb)(DOH *, DOH *), DOH *arg))(DOH *, DOH *) {
void (*old)(DOH *,DOH *);
old = (void (*)(DOH *, DOH *)) GetVoid(obj,"-trace-");
SetVoid(obj,"-trace-", (void *) cb);
if (arg)
Setattr(obj,"-tracearg-", arg);
return old;
}
/* -----------------------------------------------------------------------------
* Swig_remove_trace()
*
* Removes the tracing function from a parse tree node
* ----------------------------------------------------------------------------- */
void
Swig_remove_trace(DOH *obj) {
Delattr(obj,"-trace-");
Delattr(obj,"-tracearg-");
}
/* -----------------------------------------------------------------------------
* Swig_node_temporary()
*
* Sets a node as being temporary (deleted immediately after it is emitted)
* ----------------------------------------------------------------------------- */
void Swig_node_temporary(DOH *obj) {
SetInt(obj,"-temp-",1);
}
/* -----------------------------------------------------------------------------
* Swig_node_ignore()
*
* Causes a node to be ignored
* ----------------------------------------------------------------------------- */
void Swig_node_ignore(DOH *obj) {
SetInt(obj,"-ignore-",1);
}
/* -----------------------------------------------------------------------------
* int Swig_emit()
*
* This function calls the handler function (if any) for an object.
* ----------------------------------------------------------------------------- */
int
Swig_emit(DOH *obj, void *clientdata) {
DOH *tag;
DOH *actionobj;
char *tc;
int (*action)(DOH *obj, void *clientdata);
void (*callback)(void *clientdata);
void (*tracefunc)(DOH *obj, DOH *arg);
int ret;
assert(obj);
if (!rules) {
Printf(stderr,"No rules defined in Swig_emit()!\n");
return SWIG_ERROR;
}
if (obj) {
if (Getattr(obj,"-ignore-")) return SWIG_OK;
tag = Getattr(obj,"tag");
assert(tag);
tc = Char(tag);
while(tc) {
actionobj = Getattr(rules,tc);
if (actionobj) {
if (debug_emit) {
Printf(stderr,"Swig_emit : Matched tag '%s' -> rule '%s'\n", tag, tc);
}
/* Check for user tracing -- traces occur before any handlers are called */
tracefunc = (void (*)(DOH *, DOH *)) GetVoid(obj,"-trace-");
if (tracefunc) {
DOH *tobj = Getattr(obj,"-tracearg-");
(*tracefunc)(obj,tobj);
}
action = (int (*)(DOH *, void *)) Data(actionobj);
ret = (*action)(obj,clientdata);
/* Check for a parser callback */
callback = (void (*)(void *clientdata)) GetVoid(obj,"-callback-");
if (callback) {
void *cbarg;
cbarg = GetVoid(obj,"-callbackarg-");
(*callback)(cbarg);
Delattr(obj,"-callback-");
Delattr(obj,"-callbackarg-");
}
return ret;
} else {
tc = strchr(tc,':');
if (tc) tc++;
}
}
actionobj = Getattr(rules,"*");
if (actionobj) {
if (debug_emit) {
Printf(stderr,"Swig_emit : Matched tag '%s' -> rule '*'\n", tag);
}
/* Check for user tracing -- traces occur before any handlers are called */
tracefunc = (void (*)(DOH *, DOH *)) GetVoid(obj,"-trace-");
if (tracefunc) {
DOH *tobj = Getattr(obj,"-tracearg-");
(*tracefunc)(obj,tobj);
}
action = (int (*)(DOH *, void *)) Data(actionobj);
ret = (*action)(obj,clientdata);
/* Check for a parser callback */
callback = (void (*)(void *clientdata)) GetVoid(obj,"-callback-");
if (callback) {
void *cbarg;
cbarg = GetVoid(obj,"-callbackarg-");
(*callback)(cbarg);
Delattr(obj,"-callback-");
Delattr(obj,"-callbackarg-");
}
return ret;
}
if (debug_emit) {
Printf(stderr,"Swig_emit : No rule defined for tag '%s'\n", tag);
}
}
return SWIG_NORULE;
}
/* -----------------------------------------------------------------------------
* Swig_emit_all()
*
* Emit all of the nodes at this level.
* ----------------------------------------------------------------------------- */
int
Swig_emit_all(DOH *obj, void *clientdata) {
int ret;
while (obj) {
ret = Swig_emit(obj,clientdata);
if (ret < 0) return ret;
obj = Swig_next(obj);
}
return SWIG_OK;
}
/* -----------------------------------------------------------------------------
* Swig_node_cut()
*
* This function cuts an object out of a parse tree. To do this, the object
* MUST be properly initialized with "next", "prev", and "parent" attributes.
* ----------------------------------------------------------------------------- */
void Swig_node_cut(DOH *obj) {
DOH *parent;
DOH *next;
DOH *prev;
parent = Getattr(obj,"parent");
assert(parent);
next = Getattr(obj,"next");
prev = Getattr(obj,"prev");
DohIncref(obj); /* Make sure object doesn't go away */
Delattr(obj,"parent"); /* Disassociate from my parent */
if (!next && !prev) {
/* Well, this is a single child. Guess we'll just tell the parent that their child is gone */
Delattr(parent,"child");
return;
}
/* If no next node, then this must be at the end of a list */
if (!next) {
Delattr(prev,"next"); /* Break the 'next' link in the previous node */
Delattr(obj,"prev"); /* Break my link back to the previous object */
return;
}
/* No previous node. This must be the beginning of a list */
if (!prev) {
Delattr(next,"prev"); /* Break the 'prev' link of the next node */
Setattr(parent,"child",next); /* Update parent to point at next node */
Delattr(obj,"next"); /* Break my link to the next object */
return;
}
/* In the middle of a list someplace */
Setattr(prev,"next",next); /* Update previous node to my next node */
Setattr(next,"prev",prev); /* Update next node to my previous node */
Delattr(obj,"next");
Delattr(obj,"prev");
return;
}
/* -----------------------------------------------------------------------------
* Swig_node_insert()
*
* Inserts a node after a given node. The node to be inserted should be
* isolated (no parent, no siblings, etc...).
* ----------------------------------------------------------------------------- */
void
Swig_node_insert(DOH *node, DOH *newnode) {
DOH *next;
next = Getattr(node,"next");
if (next) {
Setattr(newnode,"next", next);
Setattr(next,"prev", newnode);
}
Setattr(node,"next",newnode);
Setattr(newnode,"prev", node);
Setattr(newnode,"parent", Getattr(node,"parent"));
}
/* -----------------------------------------------------------------------------
* Swig_node_append_child()
*
* Appends a new child to a node
* ----------------------------------------------------------------------------- */
void
Swig_node_append_child(DOH *node, DOH *chd) {
DOH *c;
DOH *pc;
c = Getattr(node,"child");
if (!c) {
Setattr(node,"child",chd);
Setattr(chd,"parent",node);
return;
}
while (c) {
pc = c;
c = Getnext(c);
}
Setattr(pc,"next",chd);
Setattr(chd,"prev",pc);
Setattr(chd,"parent",node);
}
/* -----------------------------------------------------------------------------
* Swig_count_nodes()
*
* Count number of nodes at this level
* ----------------------------------------------------------------------------- */
int Swig_count_nodes(DOH *node) {
int n = 0;
while (node) {
n++;
node = Getnext(node);
}
return n;
}