#include <stdio.h> #include <stdlib.h> static int debug = (0==0); 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 char pic[256][256]; void mknode(int nodeno, char *op, int left, int right) { ast[nodeno].op = op; ast[nodeno].left = left; ast[nodeno].right = right; } int textblit(int row, int col, char *src) { // relies on [row][col] layout. I.e. not [x][y]! 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; } 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; /* Our simple trivial-case terminal example: + -- jim | fred deltawidth = 5 ("+ -- ") deltaheight = 2 ("+, |") (spacer below rightchild) rightchildwidth = 3 rightchilddepth = 1 leftchildwidth = 4 ("fred") leftchilddepth = 1 width = 8 depth = 3 */ if (debug) fprintf(stderr, ">> %d:layout(%d, rowcol[%d][%d], depth %d, width %d);\n", id, idx, rowoff, coloff, *depth, *width); // Next hack might look like this... // // = // / \ // * . // / / \ // [] x y // / \ // 2 [] // / // 3 // TODO: implement a 'cuddle-up' procedure in both X and Y // to minimise space used // // = -- . -- y // | | // * x // | // [] - [] // | | // 2 3 // operator = ast[idx].op; leftchild = ast[idx].left; rightchild = ast[idx].right; // Anchor the corner node. deltawidth += textblit(rowoff, coloff, operator); /* not strcpy - don't copy NUL */ if (rightchild >= 0) { deltawidth += textblit(rowoff, coloff+strlen(operator), " -- "); /* not strcpy - don't copy NUL */ // 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 */ if (leftchild >= 0) { // draw the down link 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] = '|'; } // 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); #undef image } int main(int argc, char **argv) { int depth = 0, width = 0, row, col; // 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 */ 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); /* Generate layout */ layout(1, 0, 0, 0, &depth, &width); if (debug) fprintf(stderr, "Dump layout: rows = %d cols = %d\n", depth, width); if (debug) fflush(stderr); fprintf(stdout, "arrayname[5] = longvarname + structname->fieldname;\n\n"); /* display tree */ for (row = 0; row <= depth; row++) { for (col = 0; col <= width; col++) { putchar(pic[row][col]); } putchar('\n'); } /* Output from the above is: arrayname[5] = longvarname + structname->fieldname; = -- + -- -> -- fieldname | | | | | structname | | | longvarname | [] -- 5 | arrayname TODO: alternative with 'cuddle-up' and horizontal stretch: = ----- + ----- -> -- fieldname | | | [] -- 5 varname structname | longarrayname */ fflush(stdout); exit(0); return 0; }