Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Functions | Variables
jskwgen.c File Reference
#include "jsstddef.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include "jsconfig.h"
#include "jskeyword.tbl"

Go to the source code of this file.

Classes

struct  gen_opt

Defines

#define JS_KEYWORD(keyword, type, op, version)   #keyword,
#define MIN_QUOTED_CHAR_BUFFER   7

Functions

static int length_comparator (const void *a, const void *b)
static int column_comparator (const void *a, const void *b)
static unsigned count_different_lengths (unsigned indexes[], unsigned nelem)
static void find_char_span_and_count (unsigned indexes[], unsigned nelem, unsigned column, unsigned *span_result, unsigned *count_result)
static unsigned find_optimal_switch_column (struct gen_opt *opt, unsigned indexes[], unsigned nelem, unsigned columns[], unsigned unprocessed_columns, int *use_if_result)
static void p (struct gen_opt *opt, const char *format,...)
static char * qchar (char c, char *quoted_buffer)
static void nl (struct gen_opt *opt)
static void indent (struct gen_opt *opt)
static void line (struct gen_opt *opt, const char *format,...)
static void generate_letter_switch_r (struct gen_opt *opt, unsigned indexes[], unsigned nelem, unsigned columns[], unsigned unprocessed_columns)
static void generate_letter_switch (struct gen_opt *opt, unsigned indexes[], unsigned nelem, unsigned current_length)
static void generate_switch (struct gen_opt *opt)
int main (int argc, char **argv)
 The Xalan testcases app.

Variables

const char *const keyword_list []
static unsigned column_to_compare

Class Documentation

struct gen_opt

Definition at line 57 of file jskwgen.c.

Class Members
unsigned char_tail_test_threshold
unsigned indent_level
FILE * output
unsigned use_if_threshold

Define Documentation

#define JS_KEYWORD (   keyword,
  type,
  op,
  version 
)    #keyword,

Definition at line 199 of file jskwgen.c.


Function Documentation

static int column_comparator ( const void a,
const void b 
) [static]

Definition at line 79 of file jskwgen.c.

{
    const char *str1 = keyword_list[*(unsigned *)a];
    const char *str2 = keyword_list[*(unsigned *)b];
    return (int)str1[column_to_compare] - (int)str2[column_to_compare];
}

Here is the caller graph for this function:

static unsigned count_different_lengths ( unsigned  indexes[],
unsigned  nelem 
) [static]

Definition at line 87 of file jskwgen.c.

{
    unsigned nlength, current_length, i, l;

    current_length = 0;
    nlength = 0;
    for (i = 0; i != nelem; ++i) {
        l = (unsigned)strlen(keyword_list[indexes[i]]);
        assert(l != 0);
        if (current_length != l) {
            ++nlength;
            current_length = l;
        }
    }
    return nlength;
}

Here is the caller graph for this function:

static void find_char_span_and_count ( unsigned  indexes[],
unsigned  nelem,
unsigned  column,
unsigned *  span_result,
unsigned *  count_result 
) [static]

Definition at line 105 of file jskwgen.c.

{
    unsigned i, count;
    unsigned char c, prev, minc, maxc;

    assert(nelem != 0);
    minc = maxc = prev = (unsigned char)keyword_list[indexes[0]][column];
    count = 1;
    for (i = 1; i != nelem; ++i) {
        c = (unsigned char)keyword_list[indexes[i]][column];
        if (prev != c) {
            prev = c;
            ++count;
            if (minc > c) {
                minc = c;
            } else if (maxc < c) {
                maxc = c;
            }
        }
    }

    *span_result = maxc - minc + 1;
    *count_result = count;
}

Here is the caller graph for this function:

static unsigned find_optimal_switch_column ( struct gen_opt opt,
unsigned  indexes[],
unsigned  nelem,
unsigned  columns[],
unsigned  unprocessed_columns,
int use_if_result 
) [static]

Definition at line 132 of file jskwgen.c.

{
    unsigned i;
    unsigned span, min_span, min_span_index;
    unsigned nchar, min_nchar, min_nchar_index;

    assert(unprocessed_columns != 0);
    i = 0;
    min_nchar = min_span = (unsigned)-1;
    min_nchar_index = min_span_index = 0;
    do {
        column_to_compare = columns[i];
        qsort(indexes, nelem, sizeof(indexes[0]), column_comparator);
        find_char_span_and_count(indexes, nelem, column_to_compare,
                                 &span, &nchar);
        assert(span != 0);
        if (span == 1) {
            assert(nchar == 1);
            *use_if_result = 1;
            return 1;
        }
        assert(nchar != 1);
        if (min_span > span) {
            min_span = span;
            min_span_index = i;
        }
        if (min_nchar > nchar) {
            min_nchar = nchar;
            min_nchar_index = i;
        }
    } while (++i != unprocessed_columns);

    if (min_nchar <= opt->use_if_threshold) {
        *use_if_result = 1;
        i = min_nchar_index;
    } else {
        *use_if_result = 0;
        i = min_span_index;
    }

    /*
     * Restore order corresponding to i if it was destroyed by
     * subsequent sort.
     */
    if (i != unprocessed_columns - 1) {
        column_to_compare = columns[i];
        qsort(indexes, nelem, sizeof(indexes[0]), column_comparator);
    }

    return i;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void generate_letter_switch ( struct gen_opt opt,
unsigned  indexes[],
unsigned  nelem,
unsigned  current_length 
) [static]

Definition at line 349 of file jskwgen.c.

{
    unsigned *columns;
    unsigned i;

    columns = malloc(sizeof(columns[0]) * current_length);
    if (!columns) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    for (i = 0; i != current_length; ++i) {
        columns[i] = i;
    }
    generate_letter_switch_r(opt, indexes, nelem, columns, current_length);
    free(columns);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void generate_letter_switch_r ( struct gen_opt opt,
unsigned  indexes[],
unsigned  nelem,
unsigned  columns[],
unsigned  unprocessed_columns 
) [static]

Definition at line 262 of file jskwgen.c.

{
    char qbuf[MIN_QUOTED_CHAR_BUFFER];

    assert(nelem != 0);
    if (nelem == 1) {
        unsigned kw_index = indexes[0];
        const char *keyword = keyword_list[kw_index];

        if (unprocessed_columns == 0) {
            line(opt, "JSKW_GOT_MATCH(%u) /* %s */", kw_index, keyword);
        } else if (unprocessed_columns > opt->char_tail_test_threshold) {
            line(opt, "JSKW_TEST_GUESS(%u) /* %s */", kw_index, keyword);
        } else {
            unsigned i, column;

            indent(opt); p(opt, "if (");
            for (i = 0; i != unprocessed_columns; ++i) {
                column = columns[i];
                qchar(keyword[column], qbuf);
                p(opt, "%sJSKW_AT(%u)==%s", (i == 0) ? "" : " && ",
                  column, qbuf);
            }
            p(opt, ") {"); nl(opt);
            ++opt->indent_level;
            line(opt, "JSKW_GOT_MATCH(%u) /* %s */", kw_index, keyword);
            --opt->indent_level;
            line(opt, "}");
            line(opt, "JSKW_NO_MATCH()");
        }
    } else {
        unsigned optimal_column_index, optimal_column;
        unsigned i;
        int use_if;
        char current;

        assert(unprocessed_columns != 0);
        optimal_column_index = find_optimal_switch_column(opt, indexes, nelem,
                                                          columns,
                                                          unprocessed_columns,
                                                          &use_if);
        optimal_column = columns[optimal_column_index];
        columns[optimal_column_index] = columns[unprocessed_columns - 1];

        if (!use_if)
            line(opt, "switch (JSKW_AT(%u)) {", optimal_column);

        current = keyword_list[indexes[0]][optimal_column];
        for (i = 0; i != nelem;) {
            unsigned same_char_begin = i;
            char next = current;

            for (++i; i != nelem; ++i) {
                next = keyword_list[indexes[i]][optimal_column];
                if (next != current)
                    break;
            }
            qchar(current, qbuf);
            if (use_if) {
                line(opt, "if (JSKW_AT(%u) == %s) {", optimal_column, qbuf);
            } else {
                line(opt, "  case %s:", qbuf);
            }
            ++opt->indent_level;
            generate_letter_switch_r(opt, indexes + same_char_begin,
                                     i - same_char_begin,
                                     columns, unprocessed_columns - 1);
            --opt->indent_level;
            if (use_if) {
                line(opt, "}");
            }
            current = next;
        }

        if (!use_if) {
            line(opt, "}");
        }

        columns[optimal_column_index] = optimal_column;

        line(opt, "JSKW_NO_MATCH()");
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void generate_switch ( struct gen_opt opt) [static]

Definition at line 370 of file jskwgen.c.

{
    unsigned *indexes;
    unsigned nlength;
    unsigned i, current;
    int use_if;
    unsigned nelem;

    nelem = sizeof(keyword_list)/sizeof(keyword_list[0]);

    line(opt, "/*");
    line(opt, " * Generating switch for the list of %u entries:", nelem);
    for (i = 0; i != nelem; ++i) {
        line(opt, " * %s", keyword_list[i]);
    }
    line(opt, " */");

    indexes = malloc(sizeof(indexes[0]) * nelem);
    if (!indexes) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    for (i = 0; i != nelem; ++i)
        indexes[i] = i;
    qsort(indexes, nelem, sizeof(indexes[i]), length_comparator);
    nlength = count_different_lengths(indexes, nelem);

    use_if = (nlength <= opt->use_if_threshold);

    if (!use_if)
        line(opt, "switch (JSKW_LENGTH()) {");

    current = (unsigned)strlen(keyword_list[indexes[0]]);
    for (i = 0; i != nelem;) {
        unsigned same_length_begin = i;
        unsigned next = current;

        for (++i; i != nelem; ++i) {
            next = (unsigned)strlen(keyword_list[indexes[i]]);
            if (next != current)
                break;
        }
        if (use_if) {
            line(opt, "if (JSKW_LENGTH() == %u) {", current);
        } else {
            line(opt, "  case %u:", current);
        }
        ++opt->indent_level;
        generate_letter_switch(opt, indexes + same_length_begin,
                               i - same_length_begin,
                               current);
        --opt->indent_level;
        if (use_if) {
            line(opt, "}");
        }
        current = next;
    }
    if (!use_if)
        line(opt, "}");
    line(opt, "JSKW_NO_MATCH()");
    free(indexes);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void indent ( struct gen_opt opt) [static]

Definition at line 240 of file jskwgen.c.

{
    unsigned n = opt->indent_level;
    while (n != 0) {
        --n;
        fputs("    ", opt->output);
    }
}

Here is the call graph for this function:

static int length_comparator ( const void a,
const void b 
) [static]

Definition at line 71 of file jskwgen.c.

{
    const char *str1 = keyword_list[*(unsigned *)a];
    const char *str2 = keyword_list[*(unsigned *)b];
    return (int)strlen(str1) - (int)strlen(str2);
}

Here is the caller graph for this function:

static void line ( struct gen_opt opt,
const char *  format,
  ... 
) [static]

Definition at line 250 of file jskwgen.c.

{
    va_list ap;

    indent(opt);
    va_start(ap, format);
    vfprintf(opt->output, format, ap);
    va_end(ap);
    nl(opt);
}

Here is the call graph for this function:

int main ( int  argc,
char **  argv 
)

The Xalan testcases app.

Definition at line 433 of file jskwgen.c.

{
    struct gen_opt opt;

    if (argc < 2) {
        opt.output = stdout;
    } else {
        opt.output = fopen(argv[1], "w");
        if (!opt.output) {
            perror("fopen");
            exit(EXIT_FAILURE);
        }
    }
    opt.indent_level = 1;
    opt.use_if_threshold = 3;
    opt.char_tail_test_threshold = 4;

    generate_switch(&opt);

    if (opt.output != stdout) {
        if (fclose(opt.output)) {
            perror("fclose");
            exit(EXIT_FAILURE);
        }
    }

    return EXIT_SUCCESS;
}

Here is the call graph for this function:

static void nl ( struct gen_opt opt) [static]

Definition at line 234 of file jskwgen.c.

{
    putc('\n', opt->output);
}
static void p ( struct gen_opt opt,
const char *  format,
  ... 
) [static]

Definition at line 189 of file jskwgen.c.

{
    va_list ap;

    va_start(ap, format);
    vfprintf(opt->output, format, ap);
    va_end(ap);
}

Here is the call graph for this function:

static char* qchar ( char  c,
char *  quoted_buffer 
) [static]

Definition at line 202 of file jskwgen.c.

{
    char *s;

    s = quoted_buffer;
    *s++ = '\'';
    switch (c) {
      case '\n': c = 'n'; goto one_char_escape;
      case '\r': c = 'r'; goto one_char_escape;
      case '\t': c = 't'; goto one_char_escape;
      case '\f': c = 't'; goto one_char_escape;
      case '\0': c = '0'; goto one_char_escape;
      case '\'': goto one_char_escape;
      one_char_escape:
        *s++ = '\\';
        break;
      default:
        if (!isprint(c)) {
            *s++ = '\\';
            *s++ = (char)('0' + (0x3 & (((unsigned char)c) >> 6)));
            *s++ = (char)('0' + (0x7 & (((unsigned char)c) >> 3)));
            c = (char)('0' + (0x7 & ((unsigned char)c)));
        }
    }
    *s++ = c;
    *s++ = '\'';
    *s = '\0';
    assert(s + 1 <= quoted_buffer + MIN_QUOTED_CHAR_BUFFER);
    return quoted_buffer;
}

Here is the caller graph for this function:


Variable Documentation

unsigned column_to_compare [static]

Definition at line 68 of file jskwgen.c.

Definition at line 51 of file jskwgen.c.