/* CURRENTLY BEING EDITED. LOOK AT .html VERSION FOR LAST FROZEN ONE */
/* BACK IN 10 MINS... */
#include
#include
static int debug = (0!=0);
static int vertical = (0==0);
static int horizontal = (0==0);
static int wide = (0!=0);
static int trim = (0==0);
static int testone = (0==0);
static char *progname;
typedef struct
{
char *op; // '+', '-', '*', '/', etc., or terminal.
int left; // -1 means no child
int right; // ditto
} CELL;
static CELL ast[256]; // abstract syntax tree represented by a tree of
// cells
// row col
long pic[256][256]; // 0..255 is char, >= 256 is ptr to string
void mknode(int nodeno, char *op, int left, int right)
{
ast[nodeno].op = op;
ast[nodeno].left = left;
ast[nodeno].right = right;
}
int oldtextblit(int row, int col, char *src)
{
// post-processing string expansion
int l = 0;
for (;;) {
if (*src == '\0') break;
if (debug) fprintf(stderr, "1: Planting '%c' at [%d][%d]\n", *src, row, col);
pic[row][col++] = *src++;
l += 1;
}
return l;
}
int textblit(int row, int col, char *src)
{
// store pointer to string, unpack later on output
int l = strlen(src);
pic[row][col] = (int)src;
return (l+(wide?3:1))>>(wide?2:1); // half size because on diagonal
}
void layout(int id, int idx, int rowoff, int coloff, int *depth, int *width)
{
char *operator;
int leftchild, rightchild;
int leftchilddepth = 0, leftchildwidth = 0;
int rightchilddepth = 0, rightchildwidth = 0;
int deltadepth = 0, deltawidth = 0;
int i;
if (debug) fprintf(stderr, ">> %d:layout(%d, rowcol[%d][%d], depth %d, width %d);\n", id, idx, rowoff, coloff, *depth, *width);
operator = ast[idx].op;
leftchild = ast[idx].left;
rightchild = ast[idx].right;
// Anchor the corner node.
(void)textblit(rowoff, coloff, operator); /* not strcpy - don't copy NUL */
deltawidth = 1;
if (rightchild >= 0) {
int len = ((strlen(ast[leftchild].op)+(wide?3:1))>>(wide?2:1))+1; // text on the diagonal
while (len-- > 1) {deltawidth += 1; pic[rowoff][coloff-1+deltawidth] = (vertical ? '\\' : '-');}
// attach the RHS tree
if (debug) fprintf(stderr, "Recursing to right node %d\n", rightchild);
layout(2*id, rightchild, rowoff, coloff+deltawidth, &rightchilddepth, &rightchildwidth);
deltadepth = rightchilddepth;
} else {
deltadepth = 1; /* The op itself */
}
// testing: correcting a typo
if (((strlen(operator)+(wide?3:1))>>(wide?2:1)) >= deltawidth) deltawidth = ((strlen(operator)+(wide?3:1))>>(wide?2:1))+2;
if (leftchild >= 0) {
// draw the down link
// calculate extra height
if ((((strlen(ast[leftchild].op)+(wide?3:1))>>(wide?2:1))) > deltadepth) {
deltadepth = ((strlen(ast[leftchild].op)+(wide?3:1))>>(wide?2:1));
}
for (i = 1; i < deltadepth+1 /* +1 for spacer row */; i++) {
if (debug) fprintf(stderr, "2: Planting '%c' at [%d][%d]\n", '/', rowoff+i, coloff);
pic[rowoff+i][coloff] = (horizontal ? '/' : '|');
}
// recurse on the LHS tree
if (debug) fprintf(stderr, "Recursing to left node %d\n", leftchild);
layout(2*id+1, leftchild, rowoff+deltadepth+1, coloff, &leftchilddepth, &leftchildwidth);
*depth = (*depth) + leftchilddepth + deltadepth + 1;
} else *depth = (*depth) + deltadepth;
if (rightchildwidth+deltawidth > leftchildwidth) {
*width = (rightchildwidth+deltawidth);
} else {
*width = leftchildwidth;
}
if (debug) fprintf(stderr, "<< %d:layout(%d, rowcol[%d][%d], depth %d, width %d);\n", id, idx, rowoff, coloff, *depth, *width);
}
int main(int argc, char **argv)
{
int depth = 0, width = 0, row, col, offset, trimmable;
// argc is 1 if no params given
progname = argv[0];
for (;;) {
if (argc == 1) break;
argv += 1; argc -= 1; /* skip to next arg, in advance */
if (strcmp(argv[0], "-d") == 0) {
debug = (0==0);
} else if (strcmp(argv[0], "-nv") == 0) {
vertical = (0!=0);
} else if (strcmp(argv[0], "-nh") == 0) {
horizontal = (0!=0);
} else if (strcmp(argv[0], "-nt") == 0) {
trim = (0!=0);
} else if (strcmp(argv[0], "-w") == 0) {
wide = (0==0);
} else if (strcmp(argv[0], "-t1") == 0) {
testone = (0==0);
} else if (strcmp(argv[0], "-t2") == 0) {
testone = (0!=0);
} else if (strcmp(argv[0], "-h") == 0) {
fprintf(stderr, "%s:\n", progname);
fprintf(stderr, " -nh No Horizontal shear\n");
fprintf(stderr, " -nv No Vertical shear\n");
fprintf(stderr, " -nt No Trim\n");
fprintf(stderr, " -w Wide-format display\n");
fprintf(stderr, " -t1 Internal Test 1\n");
fprintf(stderr, " -t2 Internal Test 2\n");
fprintf(stderr, " -d Debug\n");
fprintf(stderr, " arg Use tree desc from file if given,\n");
fprintf(stderr, " otherwise internal test\n");
exit(0);
} else if (*argv[0] == '-') {
fprintf(stderr, "syntax: %s [-n(v|h|t)] [-w] [-t(1|2)] filename\?\n", progname);
exit(0);
} else {
argc += 1; argv -= 1;
break;
}
}
if (argc == 1) {
// internal test wanted - we can do that :-)
} else if (argc == 2) {
// argv[1] is now the actual argument, if present.
fprintf(stderr, "%s: reading from file not yet implemented\n", progname);
exit(1);
} else {
fprintf(stderr, "%s: spurious parameter %s\n", progname, argv[2]);
exit(1);
}
// Init.
for (col = 0; col < 256; col++) {
for (row = 0; row < 256; row++) {
pic[row][col] = ' ';
}
}
/* build example tree - this will actually be done by a parser */
if (testone) {
mknode(1, "[]", 5, 6);
mknode(0, "=", 1, 2);
mknode(2, "+", 3, 4);
mknode(3, "longvarname", -1, -1);
mknode(4, "->", 7, 8);
mknode(5, "arrayname", -1, -1);
mknode(6, "5", -1, -1);
mknode(7, "structname", -1, -1);
mknode(8, "fieldname", -1, -1);
} else {
mknode(1, "[]", 5, 6);
mknode(0, "=", 1, 2);
mknode(2, "+", 3, 4);
mknode(3, "a", -1, -1);
mknode(4, "->", 7, 8);
mknode(5, "b", -1, -1);
mknode(6, "5", -1, -1);
mknode(7, "c", -1, -1);
mknode(8, "d", -1, -1);
}
/* Generate layout */
layout(1, 0, 128, 0, &depth, &width);
if (debug) fprintf(stderr, "Dump layout: rows = %d cols = %d\n", depth, width);
if (debug) fflush(stderr);
if (vertical) {
/* apply vertical shear first */
offset = 1;
for (col = 1; col < 256; col++) {
// move this column down by 'offset'
for (row = 255; row > offset; row--) {
pic[row][col] = pic[row-offset][col]; pic[row-offset][col] = ' ';
}
offset += 1;
}
}
if (horizontal) {
/* apply horizontal shear next */
row = 255; // start at bottom of drawing
offset = 0;
for (;;) {
static long temp[1024];
for (col = 0; col < 256; col++) {
temp[col] = ' ';
}
for (col = 0; col < 256; col++) {
temp[col*2+offset] = pic[row][col];
temp[col*2+offset+1] = ' ';
}
for (col = 0; col < 256; col++) {
pic[row][col] = temp[col];
}
if (row == 0) break;
offset += 1; /* more shear on next row up */
row -= 1;
}
}
if (trim) {
trimmable = (0==0);
for (;;) {
for (row = 0; row < 256; row++) {
if (pic[row][0] != ' ') {
trimmable = (0!=0);
break;
}
}
if (!trimmable) break;
for (row = 0; row < 256; row++) {
for (col = 0; col+1 < 256; col++) {
pic[row][col] = pic[row][col+1];
}
pic[row][255] = ' ';
}
}
}
if (wide) {
/* apply widening last */
row = 255; // start at bottom of drawing
offset = 0;
for (;;) {
static long temp[1024];
for (col = 0; col < 256; col++) {
temp[col] = ' ';
}
for (col = 0; col < 256; col++) {
temp[col*2+offset] = pic[row][col];
temp[col*2+offset+1] = ' ';
}
for (col = 0; col < 256; col++) {
pic[row][col] = temp[col];
}
if (row == 0) break;
row -= 1;
}
}
/* display tree */
for (row = 0; row < 256; row++) {
trimmable = (0 == 0);
for (col = 0; col < 256; col++) {
if (pic[row][col] != ' ') {
trimmable = (0!=0);
break;
}
}
if (!trimmable) {
fprintf(stdout, " "); // INDENT
for (col = 255; col >= 0; col--) {
if (pic[row][col] != ' ') break;
pic[row][col] = '\0';
}
for (col = 0; col < 256; col++) {
if ((pic[row][col] < -128) || (pic[row][col] > 255)) {
oldtextblit(row, col, (char *)pic[row][col]);
} else if (pic[row][col] == '\0') break;
putchar(pic[row][col]);
}
putchar('\n');
}
}
/* Output from the above is:
=
/ \
/ +
/ / \
/ / \
/ / \
/ / \
/ / \
/ / \
/ / ->
[] longvarname / \
/ \ / \
/ \ / \
/ \ / \
/ \ / \
/ \ structname fieldname
arrayname 5
Short test produces:
=
/ \
/ +
/ / \
/ / ->
/ / / \
[] a c d
/ \
b 5
*/
fflush(stdout);
exit(0);
return 0;
}