home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Enigma Amiga Life 110
/
EnigmaAmiga110CD.iso
/
indispensabili
/
utility
/
apdf
/
xpdf-0.80
/
ltk
/
ltkbuild.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1998-11-27
|
10KB
|
473 lines
//========================================================================
//
// ltkbuild.cc
//
// Read an LTKbuild file from stdin and write C++ window construction
// function(s) to stdout.
//
// Copyright 1996 Derek B. Noonburg
//
//========================================================================
#define VERSION "0.80"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include "gtypes.h"
#include "gmem.h"
#include "GString.h"
enum ArgKind {
argVal, // arg with value
argSel, // selection arg
argLastSel // last in list of selections
};
struct ArgDesc {
char *tag; // tag used in ltk file
ArgKind kind; // kind of arg
GBool required;
char *val; // default for argVal; value for argSel
};
struct BlockDesc {
char *name; // name used in ltk file
char *type; // corresponding C++ type
ArgDesc *args; // list of legal args
};
struct Arg {
char s[256];
};
struct Block {
char *name;
char *type;
Arg *args;
int numArgs;
};
#include "ltkbuild-widgets.h"
static GBool readTopLevel();
static GBool readWindow(Block *block);
static void readBox(int indent);
static void readWidget(int indent);
static GBool readMenu(Block *block);
static void readMenuItem(int indent);
static Block *readBlock(BlockDesc *tab, char *err);
static void freeBlock(Block *block);
static void initLexer();
static char *getToken();
static GBool skipSpace();
static GBool checkToken(char *s, char *msg = NULL);
static void error(char *msg, ...);
static char line[256];
static char *nextChar;
static int lineNum;
static char tokenBuf[256];
static int numErrors;
//------------------------------------------------------------------------
int main(int argc, char *argv[]) {
initLexer();
printf("// This file was generated by ltkbuild %s\n\n", VERSION);
while (readTopLevel()) ;
if (numErrors > 0)
return 1;
return 0;
}
//------------------------------------------------------------------------
static GBool readTopLevel() {
Block *block;
GBool ok;
if (!(block = readBlock(topLevelTab, "top level block")))
return gFalse;
if (!strcmp(block->type, windowType)) {
ok = readWindow(block);
} else if (!strcmp(block->type, menuType)) {
ok = readMenu(block);
} else {
error("Internal: top-level is not Window or Menu");
freeBlock(block);
ok = gFalse;
}
return ok;
}
static GBool readWindow(Block *block) {
int i;
printf("%s *%s(LTKApp *app) {\n", block->type, block->args[0].s);
printf(" return new %s(app, ", block->type);
for (i = 1; i < block->numArgs; ++i) {
printf("%s,%c", block->args[i].s,
i < block->numArgs - 1 ? ' ' : '\n');
}
freeBlock(block);
checkToken("{");
readBox(4);
checkToken("}");
printf("\n");
printf(" );\n");
printf("}\n\n");
return gTrue;
}
static void readBox(int indent) {
Block *block;
int x, y;
int i, j;
if (!(block = readBlock(boxTab, "box block")))
return;
x = atoi(block->args[boxArgX].s);
y = atoi(block->args[boxArgY].s);
printf("%*snew %s(", indent, "", block->type);
for (i = 0; i < block->numArgs; ++i) {
printf("%s,%c", block->args[i].s,
i < block->numArgs - 1 ? ' ' : '\n');
}
freeBlock(block);
checkToken("{");
for (i = 0; i < x; ++i) {
for (j = 0; j < y; ++j) {
readWidget(indent + 2);
if (i == x-1 && j == y-1)
printf("\n");
else
printf(",\n");
}
}
checkToken("}", "wrong box size?");
printf("%*s)", indent, "");
}
static void readWidget(int indent) {
Block *block;
int x, y;
int i, j;
if (!(block = readBlock(widgetTab, "widget block")))
return;
printf("%*snew %s(", indent, "", block->type);
for (i = 0; i < block->numArgs; ++i) {
printf("%s%s", block->args[i].s,
i < block->numArgs - 1 ? ", " : "");
}
if (!strcmp(block->type, boxType)) {
x = atoi(block->args[boxArgX].s);
y = atoi(block->args[boxArgY].s);
printf(",\n");
checkToken("{");
for (i = 0; i < x; ++i) {
for (j = 0; j < y; ++j) {
readWidget(indent + 2);
if (i == x-1 && j == y-1)
printf("\n");
else
printf(",\n");
}
}
checkToken("}", "wrong box size?");
printf("%*s)", indent, "");
} else {
printf(")");
}
freeBlock(block);
}
static GBool readMenu(Block *block) {
int n, i;
printf("%s *%s() {\n", block->type, block->args[0].s);
printf(" return new %s(", block->type);
for (i = 1; i < block->numArgs; ++i) {
printf("%s,%c", block->args[i].s,
i < block->numArgs - 1 ? ' ' : '\n');
}
n = atoi(block->args[menuArgN].s);
freeBlock(block);
checkToken("{");
for (i = 0; i < n; ++i) {
readMenuItem(4);
if (i < n - 1)
printf(",\n");
else
printf("\n");
}
checkToken("}", "wrong menu size?");
printf("\n");
printf(" );\n");
printf("}\n\n");
return gTrue;
}
static void readMenuItem(int indent) {
Block *block;
int n, i;
if (!(block = readBlock(menuItemTab, "menu item block")))
return;
printf("%*snew %s(", indent, "", block->type);
for (i = 1; i < block->numArgs; ++i) {
printf("%s,", block->args[i].s);
if (i < block->numArgs - 1)
printf(" ");
}
n = atoi(block->args[0].s);
freeBlock(block);
if (n > 0) {
printf("\n");
printf("%*snew %s(NULL, %d,\n", indent + 2, "", menuType, n);
checkToken("{");
for (i = 0; i < n; ++i) {
readMenuItem(indent + 4);
if (i < n - 1)
printf(",\n");
else
printf("\n");
}
checkToken("}", "wrong menu size?");
printf("%*s)\n", indent + 2, "");
printf("%*s)", indent, "");
} else {
printf(" NULL)");
}
}
static Block *readBlock(BlockDesc *tab, char *err) {
Block *block;
char *name, *tag, *val;
BlockDesc *bd;
ArgDesc *ad;
int n;
GBool isVal;
// get name and find block descriptor
if (!(name = getToken()))
return NULL;
for (bd = tab; bd->name; ++bd) {
if (!strcmp(name, bd->name))
break;
}
if (!bd->name) {
error("Expected %s, got '%s'", err, name);
return NULL;
}
// skip paren
checkToken("(");
// allocate block
block = (Block *)gmalloc(sizeof(Block));
block->name = bd->name;
block->type = bd->type;
// count args and allocate array
block->numArgs = 0;
for (ad = bd->args; ad->tag; ++ad) {
if (ad->kind == argVal || ad->kind == argLastSel)
++block->numArgs;
}
block->args = (Arg *)gmalloc(block->numArgs * sizeof(Arg));
// initialize args to defaults
n = 0;
isVal = gTrue;
for (ad = bd->args; ad->tag; ++ad) {
if (ad->kind == argVal) {
strcpy(block->args[n++].s, ad->val);
isVal = gTrue;
} else if (isVal && ad->kind == argSel) {
strcpy(block->args[n++].s, ad->val);
isVal = gFalse;
} else if (ad->kind == argLastSel) {
isVal = gTrue;
}
}
// read args
while (1) {
if (!(tag = getToken()))
break;
if (!strcmp(tag, ")"))
break;
n = strlen(tag);
if (tag[n-1] == ':') {
tag[n-1] = '\0';
isVal = gTrue;
} else {
isVal = gFalse;
}
n = 0;
for (ad = bd->args; ad->tag; ++ad) {
if (!strcmp(ad->tag, tag))
break;
if (ad->kind == argVal || ad->kind == argLastSel)
++n;
}
if (ad->tag) {
if (isVal) {
val = getToken();
if (ad->kind != argVal)
error("Tag '%s' in '%s' block is not a value tag", tag, block->name);
} else {
val = ad->val;
if (ad->kind == argVal)
error("Tag '%s' in '%s' block is a value tag", tag, block->name);
}
strcpy(block->args[n].s, val);
} else {
error("Unknown tag '%s' in '%s' block", tag, block->name);
if (isVal)
getToken();
}
}
if (!tag)
error("Unclosed '%s' block", block->name);
return block;
}
static void freeBlock(Block *block) {
gfree(block->args);
gfree(block);
}
//------------------------------------------------------------------------
static void initLexer() {
line[0] = '\0';
nextChar = line;
lineNum = 0;
numErrors = 0;
}
static char *getToken() {
char *p;
int numBrackets;
if (!skipSpace())
return NULL;
p = tokenBuf;
if (*nextChar == '(' || *nextChar == ')' ||
*nextChar == '{' || *nextChar == '}') {
*p++ = *nextChar++;
*p = '\0';
} else if (*nextChar == '"') {
*p++ = *nextChar;
do {
++nextChar;
if (!*nextChar)
break;
*p++ = *nextChar;
} while (!(*nextChar == '"' && nextChar[-1] != '\\'));
*p = '\0';
if (*nextChar == '"')
++nextChar;
else
error("Unclosed quoted string");
} else if (*nextChar == '[') {
numBrackets = 1;
while (1) {
++nextChar;
if (!*nextChar)
break;
if (*nextChar == '[' && nextChar[-1] != '\\')
++numBrackets;
else if (*nextChar == ']' && nextChar[-1] != '\\')
--numBrackets;
if (numBrackets == 0)
break;
*p++ = *nextChar;
}
*p = '\0';
if (*nextChar == ']')
++nextChar;
else
error("Unclosed bracketed expression");
} else {
while (!isspace(*nextChar) &&
*nextChar != '(' && *nextChar != ')' &&
*nextChar != '{' && *nextChar != '}' &&
*nextChar != ':' && *nextChar)
*p++ = *nextChar++;
if (*nextChar == ':')
*p++ = *nextChar++;
*p = '\0';
}
return tokenBuf;
}
static GBool skipSpace() {
while (1) {
if (!*nextChar || *nextChar == '#') {
if (!fgets(line, sizeof(line), stdin)) {
line[0] = '\0';
nextChar = line;
return gFalse;
}
++lineNum;
nextChar = line;
} else if (isspace(*nextChar)) {
++nextChar;
} else {
break;
}
}
return gTrue;
}
static GBool checkToken(char *s, char *msg) {
char *tok;
tok = getToken();
if (tok && !strcmp(tok, s))
return gTrue;
if (msg)
error("Expected '%s', got '%s' (%s)", s, tok, msg);
else
error("Expected '%s', got '%s'", s, tok);
return gFalse;
}
static void error(char *msg, ...) {
va_list args;
fprintf(stderr, "Error at line %d: ", lineNum);
va_start(args, msg);
vfprintf(stderr, msg, args);
va_end(args);
fprintf(stderr, "\n");
++numErrors;
}