blob: 031a488a92fef8dad53f489df7cf453c9fd6d8a7 [file] [log] [blame]
/*
*(c) Copyright QNX Software Systems Ltd. 2002.
* All Rights Reserved.
*
*/
package org.eclipse.cdt.debug.mi.core;
/**
* GDB Type Parser.
* The code was lifted from: The C Programming Language
* B. W. Kernighan and D. Ritchie
*/
public class GDBTypeParser {
// GDB type parsing from whatis command
// declarator: type dcl
// type: (name)+
// dcl: ('*' | '&')* direct-decl
// direct-dcl: '(' dcl ')'
// direct-dcl '(' ')'
// direct-dcl '[' integer ']'
// name: ([a-zA-z][0-9])+
// integer ([0-9)+
final static int EOF = -1;
final static int NAME = 0;
final static int PARENS = 1;
final static int BRACKETS = 2;
String line;
int index;
int tokenType;
String token;
String dataType;
String name;
GDBDerivedType gdbDerivedType;
GDBType genericType;
public GDBType getGDBType() {
if (gdbDerivedType != null) {
return gdbDerivedType;
}
return genericType;
}
public String getVariableName() {
return name;
}
public GDBType parse(String s) {
// Sanity.
if (s == null) {
s = new String();
}
s = s.trim();
// Initialize.
line = s;
index = 0;
token = "";
dataType = "";
name = "";
gdbDerivedType = null;
// Fetch the datatype.
while (getToken() == NAME) {
dataType += " " + token;
}
// Hack for GDB, the typename can be something like
// class A : public B, C { ... } *
// We are only interreste in "class A"
int column = dataType.indexOf(':');
if (column > 0) {
dataType = dataType.substring(0, column);
}
genericType = new GDBType(dataType);
// Start the recursive parser.
dcl(tokenType);
return getGDBType();
}
public class GDBType {
public final static int GENERIC = 0;
public final static int POINTER = 1;
public final static int REFERENCE = 2;
public final static int ARRAY = 3;
public final static int FUNCTION = 4;
String nameType;
int type;
public GDBType(String n) {
this(n, 0);
}
public GDBType(int t) {
this("", t);
}
GDBType(String n, int t) {
nameType = n;
type = t;
}
public String toString() {
return nameType;
}
public String verbose() {
return nameType;
}
public int getType() {
return type;
}
}
public class GDBDerivedType extends GDBType {
int dimension;
GDBType child;
public GDBDerivedType(GDBType c, int i) {
this(c, i, 0);
}
public GDBDerivedType(GDBType c, int t, int dim) {
super(t);
setChild(c);
dimension = dim;
}
public int getDimension() {
return dimension;
}
public void setChild(GDBType c) {
child = c;
}
public GDBType getChild() {
return child;
}
public boolean hasChild() {
return child != null;
}
public String toString() {
StringBuffer sb = new StringBuffer();
String childTypeName = (hasChild() ? child.toString() : "");
sb.append(childTypeName);
switch (getType()) {
case FUNCTION :
sb.append("()");
//sb.append(" function returning " + (hasChild() ? child.toString() : ""));
break;
case ARRAY :
sb.append("[" + dimension + "]");
//sb.append(" array[" + dimension + "]" + " of " + (hasChild() ? child.toString() : ""));
break;
case REFERENCE :
sb.append("&");
//sb.append(" reference to " + (hasChild() ? child.toString() : ""));
break;
case POINTER :
sb.append("*");
//sb.append(" pointer to " + (hasChild() ? child.toString() : ""));
break;
}
return sb.toString();
}
public String verbose() {
StringBuffer sb = new StringBuffer();
switch (getType()) {
case FUNCTION :
sb.append(" function returning " + (hasChild() ? child.verbose() : ""));
break;
case ARRAY :
sb.append(" array[" + dimension + "]" + " of " + (hasChild() ? child.verbose() : ""));
break;
case REFERENCE :
sb.append(" reference to " + (hasChild() ? child.verbose() : ""));
break;
case POINTER :
sb.append(" pointer to " + (hasChild() ? child.verbose() : ""));
break;
}
return sb.toString();
}
}
int getch() {
if (index >= line.length() || index < 0) {
return EOF;
}
return line.charAt(index++);
}
void ungetch() {
if (index > 0) {
index--;
}
}
// check if the character is an alphabet
boolean isCIdentifierStart(int c) {
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || c == ':' || c == ',') {
return true;
}
return false;
}
// check is the character is alpha numeric
// [a-zA-Z0-9]
// GDB hack accept ':' ',' part of the GDB hacks
// when doing ptype gdb returns "class A : public C { ..}"
boolean isCIdentifierPart(int c) {
if ((c >= '0' && c <= 9) || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') {
return true;
}
return false;
}
boolean isCSpace(int c) {
if (c == ' ' || c == '\t' || c == '\f' || c == '\n') {
return true;
}
return false;
}
void prependChild(int kind) {
prependChild(kind, 0);
}
void prependChild(int kind, int d) {
GDBDerivedType dType = new GDBDerivedType(genericType, kind, d);
if (gdbDerivedType != null) {
// get to the last node in the list and add the new to it
GDBType leaf = genericType;
GDBDerivedType node;
boolean keepGoing = true;
for (node = gdbDerivedType; keepGoing;) {
leaf = node.getChild();
if (leaf instanceof GDBDerivedType) {
node = (GDBDerivedType) leaf;
} else {
keepGoing = false;
}
}
node.setChild(dType);
} else {
gdbDerivedType = dType;
}
}
// method returns the next token
int getToken() {
token = "";
int c = getch();
// Skip over any space
while (isCSpace(c)) {
c = getch();
}
//char character = (char) c;
if (c == '(') {
if ((c = getch()) == ')') {
token = "()";
tokenType = PARENS;
} else {
ungetch();
tokenType = '(';
}
} else if (c == '[') {
while ((c = getch()) != ']' && c != EOF) {
token += (char) c;
}
tokenType = BRACKETS;
} else if (isCIdentifierStart(c)) {
token = "" + (char) c;
while (isCIdentifierPart((c = getch())) && c != EOF) {
token += (char) c;
}
if (c != EOF) {
ungetch();
}
tokenType = NAME;
} else if (c == '{') {
// Swallow gdb sends things like "struct foobar {..} *"
// FIXME: if the bracket is not terminate do we throw exception?
int count = 1;
do {
c = getch();
if (c == '{') {
count++;
} else if (c == '}') {
count--;
}
} while (count > 0 && c != EOF);
} else {
tokenType = c;
}
return tokenType;
}
void dcl() {
dcl(getToken());
}
// parse a declarator
void dcl(int c) {
int nstar = 0;
int namp = 0;
if (c == '*') {
nstar++;
for (; getToken() == '*'; nstar++) {
}
} else if (c == '&') {
namp++;
for (; getToken() == '&'; namp++) {
}
}
dirdcl();
while (nstar-- > 0) {
prependChild(GDBType.POINTER);
}
while (namp-- > 0) {
prependChild(GDBType.REFERENCE);
}
}
// parse a direct declarator
void dirdcl() {
int type;
if (tokenType == '(') {
dcl();
if (tokenType != ')') {
// FIXME: Do we throw an exception ? not terminate parenthese
return;
}
} else if (tokenType == NAME) {
// Useless we do not need the name of the variable
name = " " + token;
} else if (tokenType == PARENS) {
prependChild(GDBType.FUNCTION);
} else if (tokenType == BRACKETS) {
int len = 0;
if (token.length() > 0) {
try {
len = Integer.parseInt(token);
} catch (NumberFormatException e) {
}
}
prependChild(GDBType.ARRAY, len);
} else {
// oops bad declaration ?
return;
}
while ((type = getToken()) == PARENS || type == BRACKETS) {
if (type == EOF) {
return;
}
if (type == PARENS) {
prependChild(GDBType.FUNCTION);
} else {
int len = 0;
if (token.length() > 0) {
try {
len = Integer.parseInt(token);
} catch (NumberFormatException e) {
}
}
prependChild(GDBType.ARRAY, len);
}
}
}
public static void main(String[] args) {
GDBTypeParser parser = new GDBTypeParser();
System.out.println("struct link { int i; int j; struct link * next} *");
parser.parse("struct link { int i; int j; struct link * next} *");
System.out.println(parser.getGDBType().verbose());
System.out.println("char **argv");
parser.parse("unsigned long long int **argv");
System.out.println(parser.getGDBType().verbose());
System.out.println("int (*daytab)[13]");
parser.parse("int (*daytab)[13]");
System.out.println(parser.getGDBType().verbose());
System.out.println("int *daytab[13]");
parser.parse("int *daytab[13]");
System.out.println(parser.getGDBType().verbose());
System.out.println("void *comp()");
parser.parse("void *comp()");
System.out.println(parser.getGDBType().verbose());
System.out.println("void (*comp)()");
parser.parse("void (*comp)()");
System.out.println(parser.getGDBType().verbose());
System.out.println("int (*func[15])()");
parser.parse("int (*func[15])()");
System.out.println(parser.getGDBType().verbose());
System.out.println("char (*(*x())[])()");
parser.parse("char (*(*x())[])()");
System.out.println(parser.getGDBType().verbose());
System.out.println("char (*(*x[3])())[5]");
parser.parse("char (*(*x[3])())[5]");
System.out.println(parser.getGDBType().verbose());
}
}