blob: 1a24c3a8120afd86e4b5df98fa0507f6482d3992 [file] [log] [blame]
/*
* Sparse c2xml
*
* Dumps the parse tree as an xml document
*
* Copyright (C) 2007 Rob Taylor
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include "expression.h"
#include "parse.h"
#include "scope.h"
#include "symbol.h"
static xmlDocPtr doc = NULL; /* document pointer */
static xmlNodePtr root_node = NULL;/* root node pointer */
static int idcount = 0;
static void examine_symbol(struct symbol *sym, xmlNodePtr node);
static xmlAttrPtr newProp(xmlNodePtr node, const char *name, const char *value)
{
return xmlNewProp(node, BAD_CAST name, BAD_CAST value);
}
static xmlAttrPtr newNumProp(xmlNodePtr node, const char *name, int value)
{
char buf[256];
snprintf(buf, 256, "%d", value);
return newProp(node, name, buf);
}
static xmlAttrPtr newIdProp(xmlNodePtr node, const char *name, unsigned int id)
{
char buf[256];
snprintf(buf, 256, "_%d", id);
return newProp(node, name, buf);
}
static xmlNodePtr new_sym_node(struct symbol *sym, const char *name, xmlNodePtr parent)
{
xmlNodePtr node;
const char *ident = show_ident(sym->ident);
assert(name != NULL);
assert(sym != NULL);
assert(parent != NULL);
node = xmlNewChild(parent, NULL, BAD_CAST "symbol", NULL);
newProp(node, "type", name);
newIdProp(node, "id", idcount);
if (sym->ident && ident)
newProp(node, "ident", ident);
newProp(node, "file", stream_name(sym->pos.stream));
newNumProp(node, "start-line", sym->pos.line);
newNumProp(node, "start-col", sym->pos.pos);
if (sym->endpos.type) {
newNumProp(node, "end-line", sym->endpos.line);
newNumProp(node, "end-col", sym->endpos.pos);
if (sym->pos.stream != sym->endpos.stream)
newProp(node, "end-file", stream_name(sym->endpos.stream));
}
sym->aux = node;
idcount++;
return node;
}
static inline void examine_members(struct symbol_list *list, xmlNodePtr node)
{
struct symbol *sym;
FOR_EACH_PTR(list, sym) {
examine_symbol(sym, node);
} END_FOR_EACH_PTR(sym);
}
static void examine_modifiers(struct symbol *sym, xmlNodePtr node)
{
const char *modifiers[] = {
"auto",
"register",
"static",
"extern",
"const",
"volatile",
"signed",
"unsigned",
"char",
"short",
"long",
"long-long",
"typedef",
NULL,
NULL,
NULL,
NULL,
NULL,
"inline",
"addressable",
"nocast",
"noderef",
"accessed",
"toplevel",
"label",
"assigned",
"type-type",
"safe",
"user-type",
"force",
"explicitly-signed",
"bitwise"};
int i;
if (sym->namespace != NS_SYMBOL)
return;
/*iterate over the 32 bit bitfield*/
for (i=0; i < 32; i++) {
if ((sym->ctype.modifiers & 1<<i) && modifiers[i])
newProp(node, modifiers[i], "1");
}
}
static void
examine_layout(struct symbol *sym, xmlNodePtr node)
{
examine_symbol_type(sym);
newNumProp(node, "bit-size", sym->bit_size);
newNumProp(node, "alignment", sym->ctype.alignment);
newNumProp(node, "offset", sym->offset);
if (is_bitfield_type(sym)) {
newNumProp(node, "bit-offset", sym->bit_offset);
}
}
static void examine_symbol(struct symbol *sym, xmlNodePtr node)
{
xmlNodePtr child = NULL;
const char *base;
int array_size;
if (!sym)
return;
if (sym->aux) /*already visited */
return;
if (sym->ident && sym->ident->reserved)
return;
child = new_sym_node(sym, get_type_name(sym->type), node);
examine_modifiers(sym, child);
examine_layout(sym, child);
if (sym->ctype.base_type) {
if ((base = builtin_typename(sym->ctype.base_type)) == NULL) {
if (!sym->ctype.base_type->aux) {
examine_symbol(sym->ctype.base_type, root_node);
}
xmlNewProp(child, BAD_CAST "base-type",
xmlGetProp((xmlNodePtr)sym->ctype.base_type->aux, BAD_CAST "id"));
} else {
newProp(child, "base-type-builtin", base);
}
}
if (sym->array_size) {
/* TODO: modify get_expression_value to give error return */
array_size = get_expression_value(sym->array_size);
newNumProp(child, "array-size", array_size);
}
switch (sym->type) {
case SYM_STRUCT:
case SYM_UNION:
examine_members(sym->symbol_list, child);
break;
case SYM_FN:
examine_members(sym->arguments, child);
break;
case SYM_UNINITIALIZED:
newProp(child, "base-type-builtin", builtin_typename(sym));
break;
default:
break;
}
return;
}
static struct position *get_expansion_end (struct token *token)
{
struct token *p1, *p2;
for (p1=NULL, p2=NULL;
!eof_token(token);
p2 = p1, p1 = token, token = token->next);
if (p2)
return &(p2->pos);
else
return NULL;
}
static void examine_macro(struct symbol *sym, xmlNodePtr node)
{
struct position *pos;
/* this should probably go in the main codebase*/
pos = get_expansion_end(sym->expansion);
if (pos)
sym->endpos = *pos;
else
sym->endpos = sym->pos;
new_sym_node(sym, "macro", node);
}
static void examine_namespace(struct symbol *sym)
{
if (sym->ident && sym->ident->reserved)
return;
switch(sym->namespace) {
case NS_MACRO:
examine_macro(sym, root_node);
break;
case NS_TYPEDEF:
case NS_STRUCT:
case NS_SYMBOL:
examine_symbol(sym, root_node);
break;
case NS_NONE:
case NS_LABEL:
case NS_ITERATOR:
case NS_UNDEF:
case NS_PREPROCESSOR:
case NS_KEYWORD:
break;
default:
die("Unrecognised namespace type %d",sym->namespace);
}
}
static int get_stream_id (const char *name)
{
int i;
for (i=0; i<input_stream_nr; i++) {
if (strcmp(name, stream_name(i))==0)
return i;
}
return -1;
}
static inline void examine_symbol_list(const char *file, struct symbol_list *list)
{
struct symbol *sym;
int stream_id = get_stream_id (file);
if (!list)
return;
FOR_EACH_PTR(list, sym) {
if (sym->pos.stream == stream_id)
examine_namespace(sym);
} END_FOR_EACH_PTR(sym);
}
int main(int argc, char **argv)
{
struct string_list *filelist = NULL;
struct symbol_list *symlist = NULL;
char *file;
doc = xmlNewDoc(BAD_CAST "1.0");
root_node = xmlNewNode(NULL, BAD_CAST "parse");
xmlDocSetRootElement(doc, root_node);
/* - A DTD is probably unnecessary for something like this
dtd = xmlCreateIntSubset(doc, "parse", "http://www.kernel.org/pub/software/devel/sparse/parse.dtd" NULL, "parse.dtd");
ns = xmlNewNs (root_node, "http://www.kernel.org/pub/software/devel/sparse/parse.dtd", NULL);
xmlSetNs(root_node, ns);
*/
symlist = sparse_initialize(argc, argv, &filelist);
FOR_EACH_PTR(filelist, file) {
examine_symbol_list(file, symlist);
sparse_keep_tokens(file);
examine_symbol_list(file, file_scope->symbols);
examine_symbol_list(file, global_scope->symbols);
} END_FOR_EACH_PTR(file);
xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);
xmlFreeDoc(doc);
xmlCleanupParser();
return 0;
}