195 lines
5.4 KiB
C
Executable File
195 lines
5.4 KiB
C
Executable File
/* first.c - Phase I, input data preprocessing */
|
|
|
|
/* Written 1995-1997 by Werner Almesberger, EPFL-LRC */
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include "common.h"
|
|
#include "qgen.h"
|
|
#include "file.h"
|
|
|
|
|
|
int field = 0;
|
|
int group = 0;
|
|
int offset = 0;
|
|
int varlen_fields = 0;
|
|
|
|
static unsigned char mask = 0;
|
|
static int seq = 0;
|
|
|
|
|
|
#define ALLOC(field) ({ \
|
|
if (mask & beg_mask) \
|
|
die("bit collision (%s: 0x%02X+0x%02X)",walk->id,mask,beg_mask); \
|
|
field->pos += offset; \
|
|
if (next <= 8) { \
|
|
mask |= end_mask; \
|
|
walk->jump = 0; \
|
|
} \
|
|
else { \
|
|
mask = end_mask; \
|
|
walk->jump = (next-1) >> 3; \
|
|
} \
|
|
if (walk->flush && walk->size) { \
|
|
if (!mask) die("nothing to flush (%s)",walk->id); \
|
|
walk->jump++; \
|
|
mask = 0; \
|
|
} })
|
|
|
|
|
|
static void process(FIELD *start,int defines)
|
|
{
|
|
FIELD *walk;
|
|
TAG *scan;
|
|
unsigned char beg_mask,end_mask,orig_mask;
|
|
int tmp,shift,next;
|
|
|
|
for (walk = start; walk; walk = walk->next) {
|
|
walk->field = field; /* record it even if this isn't a real field (we
|
|
need to know the first field number later in
|
|
second.c and this way we don't have to search
|
|
for it) */
|
|
if (walk->structure) {
|
|
int start_field,start_group;
|
|
|
|
start_field = field;
|
|
start_group = group;
|
|
process(walk->my_block,walk->structure->instances > 0);
|
|
if (walk->structure->instances > 1) {
|
|
walk->structure->instances = -1;
|
|
walk->structure->first_field = start_field;
|
|
walk->structure->fields = field-start_field;
|
|
walk->structure->groups = group-start_group;
|
|
}
|
|
continue;
|
|
}
|
|
walk->seq = seq++; /* number of fields, always increases */
|
|
if (*walk->id != '_') {
|
|
if (defines) to_h("#define QF_%s %d\n",walk->id,field);
|
|
to_test(" \"%s\",\n",walk->id);
|
|
field++;
|
|
}
|
|
if (mask && walk->brk)
|
|
die("mask 0x%02x at break (%s)\n",mask,walk->id);
|
|
/* compute position and adjust masks */
|
|
tmp = walk->size > 7 ? 0xff : (1 << walk->size)-1;
|
|
beg_mask = tmp << walk->pos;
|
|
tmp = 0xff & ~((1 << (8-(walk->size & 7)))-1);
|
|
if (walk->size && !tmp) tmp = 0xff;
|
|
next = walk->pos+walk->size;
|
|
shift = 8-(next & 7);
|
|
if (shift == 8) shift = 0;
|
|
end_mask = tmp >> shift;
|
|
if (debug)
|
|
printf("mask 0x%02X, beg 0x%02X, end 0x%02X, offset %d, flush %d, "
|
|
"%s\n",mask,beg_mask,end_mask,offset,walk->flush,walk->id);
|
|
/* handle values */
|
|
if (!walk->value) {
|
|
if (walk->var_len == -2) walk->var_len = varlen_fields++;
|
|
ALLOC(walk);
|
|
offset += walk->jump*8;
|
|
}
|
|
else switch (walk->value->type) {
|
|
case vt_id:
|
|
ALLOC(walk);
|
|
to_c(" q_put(q_initial,%d,%d,%s); /* %s */\n",walk->pos,
|
|
walk->size,walk->value->id,walk->id);
|
|
offset += walk->jump*8;
|
|
break;
|
|
case vt_case:
|
|
if (*walk->id != '_') {
|
|
ALLOC(walk);
|
|
offset += walk->jump*8;
|
|
#if 0 /* bad idea */
|
|
for (scan = walk->value->tags; scan; scan = scan->next)
|
|
if (scan->deflt) {
|
|
to_c(" q_put(q_initial,%d,%d,%s); "
|
|
"/* %s */\n",walk->pos,walk->size,
|
|
scan->value,walk->id);
|
|
}
|
|
#endif
|
|
}
|
|
/* fall through */
|
|
#if 0
|
|
if (*walk->id != '_') {
|
|
ALLOC(walk);
|
|
offset += walk->jump*8;
|
|
orig_mask = mask;
|
|
for (scan = walk->value->tags; scan; scan = scan->next)
|
|
{
|
|
if (scan->id && defines)
|
|
to_h("#define QG_%s %d\n",scan->id,-group-1);
|
|
scan->group = group++;
|
|
scan->pos = walk->pos;
|
|
mask = orig_mask;
|
|
to_c(" q_put(q_initial,%d,%d,%s); /* %s */\n",
|
|
walk->pos,walk->size,scan->value,walk->id);
|
|
process(scan->block,defines);
|
|
if (mask) offset += 8;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
/* fall through */
|
|
case vt_multi:
|
|
orig_mask = mask;
|
|
for (scan = walk->value->tags; scan; scan = scan->next) {
|
|
if (scan->id && defines)
|
|
to_h("#define QG_%s %d\n",scan->id,-group-1);
|
|
scan->group = group++;
|
|
scan->pos = walk->pos;
|
|
if (debug)
|
|
printf("| %s/%s (walk->flush = %d)\n",walk->id,
|
|
scan->value,walk->flush);
|
|
if (*walk->id != '_') mask = orig_mask;
|
|
else {
|
|
ALLOC(scan);
|
|
if (debug)
|
|
printf("| jump = %d (mask 0x%02x)\n",
|
|
walk->jump,mask);
|
|
offset += walk->jump*8;
|
|
to_c(" q_put(q_initial,%d,%d,%s); /* %s */\n",
|
|
scan->pos,walk->size,scan->value,walk->id);
|
|
}
|
|
process(scan->block,defines);
|
|
if (*walk->id != '_' && mask) die("EF129");
|
|
}
|
|
break;
|
|
case vt_length:
|
|
ALLOC(walk);
|
|
offset += walk->jump*8;
|
|
process(walk->value->block,defines);
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void first(FIELD *def)
|
|
{
|
|
def->group = group++;
|
|
to_h("/*\n * Identifiers to access numbers of fields and of named\n");
|
|
to_h(" * groups (unnamed groups don't need that). Field numbers are\n");
|
|
to_h(" * zero-based. Group numbers are negative and -1-based.\n */\n\n");
|
|
to_c("static unsigned char q_initial[Q_DATA_BYTES];\n\n");
|
|
to_c("/*\n * Initialization of constant data. Could also do this in\n");
|
|
to_c(" * the translator and output the resulting byte stream.\n */\n\n");
|
|
to_c("static void q_init_global(void)\n{\n");
|
|
to_c(" memset(q_initial,0,sizeof(q_initial));\n");
|
|
to_test("static const char *fields[] = {\n");
|
|
process(def,1);
|
|
to_test(" NULL\n};\n\n");
|
|
to_c("}\n\n");
|
|
if (mask) offset += 8;
|
|
to_h("\n/*\n * Sizes of various tables which are allocated at run-time.\n");
|
|
to_h(" */\n");
|
|
to_h("\n#define Q_DATA_BYTES %d\n",offset/8);
|
|
to_h("#define Q_GROUPS %d\n",group);
|
|
to_h("#define Q_FIELDS %d\n",field);
|
|
to_h("#define Q_VARLEN_FIELDS %d\n\n",varlen_fields);
|
|
}
|