git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@960 626c5289-ae23-0410-ae9c-e8d60b6d4f22
513 lines
14 KiB
C
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|