Annotation of embedaddon/ntp/ntpd/keyword-gen.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * keyword-gen.c -- generate keyword scanner finite state machine and
        !             3:  *                 keyword_text array.
        !             4:  *                 This program is run to generate ntp_keyword.h
        !             5:  */
        !             6: #include <config.h>
        !             7: #include <stdio.h>
        !             8: #include <stdlib.h>
        !             9: #include <time.h>
        !            10: 
        !            11: #include <ntp_stdlib.h>
        !            12: #include <ntp_config.h>
        !            13: #include <lib_strbuf.h>
        !            14: #include "ntp_scanner.h"
        !            15: #include "ntp_parser.h"
        !            16: 
        !            17: 
        !            18: #ifdef QSORT_USES_VOID_P
        !            19: typedef const void *   QSORTP;
        !            20: #else
        !            21: typedef char *         QSORTP;
        !            22: #endif
        !            23: 
        !            24: /* Define a structure to hold a (keyword, token) pair */
        !            25: struct key_tok {
        !            26:        char *  key;            /* Keyword */
        !            27:        int     token;          /* Associated Token */
        !            28:        follby  followedby;     /* nonzero indicates the next token(s)
        !            29:                                   forced to be string(s) */
        !            30: };
        !            31: 
        !            32: struct key_tok ntp_keywords[] = {
        !            33: { "...",               T_Ellipsis,             FOLLBY_TOKEN },
        !            34: { "automax",           T_Automax,              FOLLBY_TOKEN },
        !            35: { "broadcast",         T_Broadcast,            FOLLBY_STRING },
        !            36: { "broadcastclient",   T_Broadcastclient,      FOLLBY_TOKEN },
        !            37: { "broadcastdelay",    T_Broadcastdelay,       FOLLBY_TOKEN },
        !            38: { "calldelay",         T_Calldelay,            FOLLBY_TOKEN },
        !            39: { "disable",           T_Disable,              FOLLBY_TOKEN },
        !            40: { "driftfile",         T_Driftfile,            FOLLBY_STRING },
        !            41: { "enable",            T_Enable,               FOLLBY_TOKEN },
        !            42: { "end",               T_End,                  FOLLBY_TOKEN },
        !            43: { "filegen",           T_Filegen,              FOLLBY_TOKEN },
        !            44: { "fudge",             T_Fudge,                FOLLBY_STRING },
        !            45: { "includefile",       T_Includefile,          FOLLBY_STRING },
        !            46: { "leapfile",          T_Leapfile,             FOLLBY_STRING },
        !            47: { "logconfig",         T_Logconfig,            FOLLBY_STRINGS_TO_EOC },
        !            48: { "logfile",           T_Logfile,              FOLLBY_STRING },
        !            49: { "manycastclient",    T_Manycastclient,       FOLLBY_STRING },
        !            50: { "manycastserver",    T_Manycastserver,       FOLLBY_STRINGS_TO_EOC },
        !            51: { "multicastclient",   T_Multicastclient,      FOLLBY_STRINGS_TO_EOC },
        !            52: { "peer",              T_Peer,                 FOLLBY_STRING },
        !            53: { "phone",             T_Phone,                FOLLBY_STRINGS_TO_EOC },
        !            54: { "pidfile",           T_Pidfile,              FOLLBY_STRING },
        !            55: { "pool",              T_Pool,                 FOLLBY_STRING },
        !            56: { "discard",           T_Discard,              FOLLBY_TOKEN },
        !            57: { "restrict",          T_Restrict,             FOLLBY_TOKEN },
        !            58: { "server",            T_Server,               FOLLBY_STRING },
        !            59: { "setvar",            T_Setvar,               FOLLBY_STRING },
        !            60: { "statistics",                T_Statistics,           FOLLBY_TOKEN },
        !            61: { "statsdir",          T_Statsdir,             FOLLBY_STRING },
        !            62: { "tick",              T_Tick,                 FOLLBY_TOKEN },
        !            63: { "tinker",            T_Tinker,               FOLLBY_TOKEN },
        !            64: { "tos",               T_Tos,                  FOLLBY_TOKEN },
        !            65: { "trap",              T_Trap,                 FOLLBY_STRING },
        !            66: { "unconfig",          T_Unconfig,             FOLLBY_STRING },
        !            67: { "unpeer",            T_Unpeer,               FOLLBY_STRING },
        !            68: /* authentication_command */
        !            69: { "controlkey",                T_ControlKey,           FOLLBY_TOKEN },
        !            70: { "crypto",            T_Crypto,               FOLLBY_TOKEN },
        !            71: { "keys",              T_Keys,                 FOLLBY_STRING },
        !            72: { "keysdir",           T_Keysdir,              FOLLBY_STRING },
        !            73: { "ntpsigndsocket",    T_NtpSignDsocket,       FOLLBY_STRING },
        !            74: { "requestkey",                T_Requestkey,           FOLLBY_TOKEN },
        !            75: { "revoke",            T_Revoke,               FOLLBY_TOKEN },
        !            76: { "trustedkey",                T_Trustedkey,           FOLLBY_TOKEN },
        !            77: /* IPv4/IPv6 protocol override flag */
        !            78: { "-4",                        T_Ipv4_flag,            FOLLBY_TOKEN },
        !            79: { "-6",                        T_Ipv6_flag,            FOLLBY_TOKEN },
        !            80: /* option */
        !            81: { "autokey",           T_Autokey,              FOLLBY_TOKEN },
        !            82: { "bias",              T_Bias,                 FOLLBY_TOKEN },
        !            83: { "burst",             T_Burst,                FOLLBY_TOKEN },
        !            84: { "iburst",            T_Iburst,               FOLLBY_TOKEN },
        !            85: { "key",               T_Key,                  FOLLBY_TOKEN },
        !            86: { "maxpoll",           T_Maxpoll,              FOLLBY_TOKEN },
        !            87: { "minpoll",           T_Minpoll,              FOLLBY_TOKEN },
        !            88: { "mode",              T_Mode,                 FOLLBY_TOKEN },
        !            89: { "noselect",          T_Noselect,             FOLLBY_TOKEN },
        !            90: { "preempt",           T_Preempt,              FOLLBY_TOKEN },
        !            91: { "true",              T_True,                 FOLLBY_TOKEN },
        !            92: { "prefer",            T_Prefer,               FOLLBY_TOKEN },
        !            93: { "ttl",               T_Ttl,                  FOLLBY_TOKEN },
        !            94: { "version",           T_Version,              FOLLBY_TOKEN },
        !            95: { "xleave",            T_Xleave,               FOLLBY_TOKEN },
        !            96: /* crypto_command */
        !            97: { "host",              T_Host,                 FOLLBY_STRING },
        !            98: { "ident",             T_Ident,                FOLLBY_STRING },
        !            99: { "pw",                        T_Pw,                   FOLLBY_STRING },
        !           100: { "randfile",          T_Randfile,             FOLLBY_STRING },
        !           101: { "sign",              T_Sign,                 FOLLBY_STRING },
        !           102: { "digest",            T_Digest,               FOLLBY_STRING },
        !           103: /*** MONITORING COMMANDS ***/
        !           104: /* stat */
        !           105: { "clockstats",                T_Clockstats,           FOLLBY_TOKEN },
        !           106: { "cryptostats",       T_Cryptostats,          FOLLBY_TOKEN },
        !           107: { "loopstats",         T_Loopstats,            FOLLBY_TOKEN },
        !           108: { "peerstats",         T_Peerstats,            FOLLBY_TOKEN },
        !           109: { "rawstats",          T_Rawstats,             FOLLBY_TOKEN },
        !           110: { "sysstats",          T_Sysstats,             FOLLBY_TOKEN },
        !           111: { "protostats",                T_Protostats,           FOLLBY_TOKEN },
        !           112: { "timingstats",       T_Timingstats,          FOLLBY_TOKEN },
        !           113: /* filegen_option */
        !           114: { "file",              T_File,                 FOLLBY_STRING },
        !           115: { "link",              T_Link,                 FOLLBY_TOKEN },
        !           116: { "nolink",            T_Nolink,               FOLLBY_TOKEN },
        !           117: { "type",              T_Type,                 FOLLBY_TOKEN },
        !           118: /* filegen_type */
        !           119: { "age",               T_Age,                  FOLLBY_TOKEN },
        !           120: { "day",               T_Day,                  FOLLBY_TOKEN },
        !           121: { "month",             T_Month,                FOLLBY_TOKEN },
        !           122: { "none",              T_None,                 FOLLBY_TOKEN },
        !           123: { "pid",               T_Pid,                  FOLLBY_TOKEN },
        !           124: { "week",              T_Week,                 FOLLBY_TOKEN },
        !           125: { "year",              T_Year,                 FOLLBY_TOKEN },
        !           126: /*** ORPHAN MODE COMMANDS ***/
        !           127: /* tos_option */
        !           128: { "minclock",          T_Minclock,             FOLLBY_TOKEN },
        !           129: { "maxclock",          T_Maxclock,             FOLLBY_TOKEN },
        !           130: { "minsane",           T_Minsane,              FOLLBY_TOKEN },
        !           131: { "floor",             T_Floor,                FOLLBY_TOKEN },
        !           132: { "ceiling",           T_Ceiling,              FOLLBY_TOKEN },
        !           133: { "cohort",            T_Cohort,               FOLLBY_TOKEN },
        !           134: { "mindist",           T_Mindist,              FOLLBY_TOKEN },
        !           135: { "maxdist",           T_Maxdist,              FOLLBY_TOKEN },
        !           136: { "beacon",            T_Beacon,               FOLLBY_TOKEN },
        !           137: { "orphan",            T_Orphan,               FOLLBY_TOKEN },
        !           138: /* access_control_flag */
        !           139: { "default",           T_Default,              FOLLBY_TOKEN },
        !           140: { "flake",             T_Flake,                FOLLBY_TOKEN },
        !           141: { "ignore",            T_Ignore,               FOLLBY_TOKEN },
        !           142: { "limited",           T_Limited,              FOLLBY_TOKEN },
        !           143: { "mssntp",            T_Mssntp,               FOLLBY_TOKEN },
        !           144: { "kod",               T_Kod,                  FOLLBY_TOKEN },
        !           145: { "lowpriotrap",       T_Lowpriotrap,          FOLLBY_TOKEN },
        !           146: { "mask",              T_Mask,                 FOLLBY_TOKEN },
        !           147: { "nomodify",          T_Nomodify,             FOLLBY_TOKEN },
        !           148: { "nopeer",            T_Nopeer,               FOLLBY_TOKEN },
        !           149: { "noquery",           T_Noquery,              FOLLBY_TOKEN },
        !           150: { "noserve",           T_Noserve,              FOLLBY_TOKEN },
        !           151: { "notrap",            T_Notrap,               FOLLBY_TOKEN },
        !           152: { "notrust",           T_Notrust,              FOLLBY_TOKEN },
        !           153: { "ntpport",           T_Ntpport,              FOLLBY_TOKEN },
        !           154: /* discard_option */
        !           155: { "average",           T_Average,              FOLLBY_TOKEN },
        !           156: { "minimum",           T_Minimum,              FOLLBY_TOKEN },
        !           157: { "monitor",           T_Monitor,              FOLLBY_TOKEN },
        !           158: /* fudge_factor */
        !           159: { "flag1",             T_Flag1,                FOLLBY_TOKEN },
        !           160: { "flag2",             T_Flag2,                FOLLBY_TOKEN },
        !           161: { "flag3",             T_Flag3,                FOLLBY_TOKEN },
        !           162: { "flag4",             T_Flag4,                FOLLBY_TOKEN },
        !           163: { "refid",             T_Refid,                FOLLBY_STRING },
        !           164: { "stratum",           T_Stratum,              FOLLBY_TOKEN },
        !           165: { "time1",             T_Time1,                FOLLBY_TOKEN },
        !           166: { "time2",             T_Time2,                FOLLBY_TOKEN },
        !           167: /* system_option */
        !           168: { "auth",              T_Auth,                 FOLLBY_TOKEN },
        !           169: { "bclient",           T_Bclient,              FOLLBY_TOKEN },
        !           170: { "calibrate",         T_Calibrate,            FOLLBY_TOKEN },
        !           171: { "kernel",            T_Kernel,               FOLLBY_TOKEN },
        !           172: { "ntp",               T_Ntp,                  FOLLBY_TOKEN },
        !           173: { "stats",             T_Stats,                FOLLBY_TOKEN },
        !           174: /* tinker_option */
        !           175: { "step",              T_Step,                 FOLLBY_TOKEN },
        !           176: { "panic",             T_Panic,                FOLLBY_TOKEN },
        !           177: { "dispersion",                T_Dispersion,           FOLLBY_TOKEN },
        !           178: { "stepout",           T_Stepout,              FOLLBY_TOKEN },
        !           179: { "allan",             T_Allan,                FOLLBY_TOKEN },
        !           180: { "huffpuff",          T_Huffpuff,             FOLLBY_TOKEN },
        !           181: { "freq",              T_Freq,                 FOLLBY_TOKEN },
        !           182: /* miscellaneous_command */
        !           183: { "port",              T_Port,                 FOLLBY_TOKEN },
        !           184: { "interface",         T_Interface,            FOLLBY_TOKEN },
        !           185: { "qos",               T_Qos,                  FOLLBY_TOKEN },
        !           186: { "saveconfigdir",     T_Saveconfigdir,        FOLLBY_STRING },
        !           187: /* interface_command (ignore and interface already defined) */
        !           188: { "nic",               T_Nic,                  FOLLBY_TOKEN },
        !           189: { "all",               T_All,                  FOLLBY_TOKEN },
        !           190: { "ipv4",              T_Ipv4,                 FOLLBY_TOKEN },
        !           191: { "ipv6",              T_Ipv6,                 FOLLBY_TOKEN },
        !           192: { "wildcard",          T_Wildcard,             FOLLBY_TOKEN },
        !           193: { "listen",            T_Listen,               FOLLBY_TOKEN },
        !           194: { "drop",              T_Drop,                 FOLLBY_TOKEN },
        !           195: /* simulator commands */
        !           196: { "simulate",          T_Simulate,             FOLLBY_TOKEN },
        !           197: { "simulation_duration",T_Sim_Duration,                FOLLBY_TOKEN },
        !           198: { "beep_delay",                T_Beep_Delay,           FOLLBY_TOKEN },
        !           199: { "duration",          T_Duration,             FOLLBY_TOKEN },
        !           200: { "server_offset",     T_Server_Offset,        FOLLBY_TOKEN },
        !           201: { "freq_offset",       T_Freq_Offset,          FOLLBY_TOKEN },
        !           202: { "wander",            T_Wander,               FOLLBY_TOKEN },
        !           203: { "jitter",            T_Jitter,               FOLLBY_TOKEN },
        !           204: { "prop_delay",                T_Prop_Delay,           FOLLBY_TOKEN },
        !           205: { "proc_delay",                T_Proc_Delay,           FOLLBY_TOKEN },
        !           206: };
        !           207: 
        !           208: 
        !           209: typedef struct big_scan_state_tag {
        !           210:        char    ch;             /* Character this state matches on */
        !           211:        char    followedby;     /* Forces next token(s) to T_String */
        !           212:        u_short finishes_token; /* nonzero ID if last keyword char */
        !           213:        u_short match_next_s;   /* next state to check matching ch */
        !           214:        u_short other_next_s;   /* next state to check if not ch */
        !           215: } big_scan_state;
        !           216: 
        !           217: /*
        !           218:  * Note: to increase MAXSTATES beyond 2048, be aware it is currently
        !           219:  * crammed into 11 bits in scan_state form.  Raising to 4096 would be
        !           220:  * relatively easy by storing the followedby value in a separate
        !           221:  * array with one entry per token, and shrinking the char value to
        !           222:  * 7 bits to free a bit for accepting/non-accepting.  More than 4096
        !           223:  * states will require expanding scan_state beyond 32 bits each.
        !           224:  */
        !           225: #define MAXSTATES 2048
        !           226: 
        !           227: const char *   current_keyword;/* for error reporting */
        !           228: big_scan_state sst[MAXSTATES]; /* scanner FSM state entries */
        !           229: int            sst_highwater;  /* next entry index to consider */
        !           230: char *         symb[1024];     /* map token ID to symbolic name */
        !           231: 
        !           232: /* for libntp */
        !           233: const char *   progname = "keyword-gen";
        !           234: volatile int   debug = 1;
        !           235: 
        !           236: int            main                    (int, char **);
        !           237: static void    generate_preamble       (void);
        !           238: static void    generate_fsm            (void);
        !           239: static void    generate_token_text     (void);
        !           240: static int     create_keyword_scanner  (void);
        !           241: static int     create_scan_states      (char *, int, follby, int);
        !           242: int            compare_key_tok_id      (QSORTP, QSORTP);
        !           243: int            compare_key_tok_text    (QSORTP, QSORTP);
        !           244: void           populate_symb           (char *);
        !           245: const char *   symbname                (int);
        !           246: 
        !           247: 
        !           248: int main(int argc, char **argv)
        !           249: {
        !           250:        if (argc < 2) {
        !           251:                fprintf(stderr, "Usage:\n%s t_header.h\n", argv[0]);
        !           252:                exit(1);
        !           253:        }
        !           254:        populate_symb(argv[1]);
        !           255: 
        !           256:        generate_preamble();
        !           257:        generate_token_text();
        !           258:        generate_fsm();
        !           259: 
        !           260:        return 0;
        !           261: }
        !           262: 
        !           263: 
        !           264: static void
        !           265: generate_preamble(void)
        !           266: {
        !           267:        time_t now;
        !           268:        char timestamp[128];
        !           269:        char preamble[] =
        !           270: "/*\n"
        !           271: " * ntp_keyword.h\n"
        !           272: " * \n"
        !           273: " * NOTE: edit this file with caution, it is generated by keyword-gen.c\n"
        !           274: " *\t Generated %s UTC   diff_ignore_line\n"
        !           275: " *\n"
        !           276: " */\n"
        !           277: "#include \"ntp_scanner.h\"\n"
        !           278: "#include \"ntp_parser.h\"\n"
        !           279: "\n";
        !           280: 
        !           281:        time(&now);
        !           282:        if (!strftime(timestamp, sizeof(timestamp),
        !           283:                      "%Y-%m-%d %H:%M:%S", gmtime(&now)))
        !           284:                timestamp[0] = '\0';
        !           285: 
        !           286:        printf(preamble, timestamp);
        !           287: }
        !           288: 
        !           289: 
        !           290: static void
        !           291: generate_fsm(void)
        !           292: {
        !           293:        char token_id_comment[128];
        !           294:        int initial_state;
        !           295:        int i;
        !           296:        int token;
        !           297: 
        !           298:        /* 
        !           299:         * Sort ntp_keywords in alphabetical keyword order.  This is
        !           300:         * not necessary, but minimizes nonfunctional changes in the
        !           301:         * generated finite state machine when keywords are modified.
        !           302:         */
        !           303:        qsort(ntp_keywords, COUNTOF(ntp_keywords),
        !           304:              sizeof(ntp_keywords[0]), compare_key_tok_text);
        !           305: 
        !           306:        /*
        !           307:         * To save space, reserve the state array entry matching each 
        !           308:         * token number for its terminal state, so the token identifier
        !           309:         * does not need to be stored in each state, but can be
        !           310:         * recovered trivially.  To mark the entry reserved,
        !           311:         * finishes_token is nonzero.
        !           312:         */
        !           313: 
        !           314:        for (i = 0; i < COUNTOF(ntp_keywords); i++) {
        !           315:                token = ntp_keywords[i].token;
        !           316:                if (1 > token || token >= COUNTOF(sst)) {
        !           317:                        fprintf(stderr,
        !           318:                                "keyword-gen sst[%u] too small "
        !           319:                                "for keyword '%s' id %d\n",
        !           320:                                COUNTOF(sst),
        !           321:                                ntp_keywords[i].key,
        !           322:                                token);
        !           323:                        exit(4);
        !           324:                }
        !           325:                sst[token].finishes_token = token;
        !           326:        }
        !           327: 
        !           328:        initial_state = create_keyword_scanner();
        !           329: 
        !           330:        fprintf(stderr,
        !           331:                "%d keywords consumed %d states of %d max.\n",
        !           332:                (int)COUNTOF(ntp_keywords),
        !           333:                sst_highwater - 1,
        !           334:                (int)COUNTOF(sst) - 1);
        !           335: 
        !           336:        printf("#define SCANNER_INIT_S %d\n\n", initial_state);
        !           337: 
        !           338:        printf("const scan_state sst[%d] = {\n"
        !           339:               "/*SS_T( ch,\tf-by, match, other ),\t\t\t\t */\n"
        !           340:               "  0,\t\t\t\t      /* %5d %-17s */\n",
        !           341:               sst_highwater,
        !           342:               0, "");
        !           343: 
        !           344:        for (i = 1; i < sst_highwater; i++) {
        !           345: 
        !           346:                /* verify fields will fit */
        !           347:                if (sst[i].followedby & ~0x3) {
        !           348:                        fprintf(stderr,
        !           349:                                "keyword-gen internal error "
        !           350:                                "sst[%d].followedby %d too big\n",
        !           351:                                i, sst[i].followedby);
        !           352:                        exit(7);
        !           353:                }
        !           354: 
        !           355:                if (sst_highwater <= sst[i].match_next_s
        !           356:                    || sst[i].match_next_s & ~0x7ff) {
        !           357:                        fprintf(stderr,
        !           358:                                "keyword-gen internal error "
        !           359:                                "sst[%d].match_next_s %d too big\n",
        !           360:                                i, sst[i].match_next_s);
        !           361:                        exit(8);
        !           362:                }
        !           363: 
        !           364:                if (sst_highwater <= sst[i].other_next_s
        !           365:                    || sst[i].other_next_s & ~0x7ff) {
        !           366:                        fprintf(stderr,
        !           367:                                "keyword-gen internal error "
        !           368:                                "sst[%d].other_next_s %d too big\n",
        !           369:                                i, sst[i].other_next_s);
        !           370:                        exit(9);
        !           371:                }
        !           372: 
        !           373:                if (!sst[i].finishes_token)
        !           374:                        snprintf(token_id_comment,
        !           375:                                 sizeof(token_id_comment), "%5d %-17s",
        !           376:                                 i, (initial_state == i) 
        !           377:                                        ? "initial state" 
        !           378:                                        : "");
        !           379:                else {
        !           380:                        snprintf(token_id_comment, 
        !           381:                                 sizeof(token_id_comment), "%5d %-17s",
        !           382:                                 i, symbname(sst[i].finishes_token));
        !           383:                        if (i != sst[i].finishes_token) {
        !           384:                                fprintf(stderr,
        !           385:                                        "keyword-gen internal error "
        !           386:                                        "entry %d finishes token %d\n",
        !           387:                                        i, sst[i].finishes_token);
        !           388:                                exit(5);
        !           389:                        }
        !           390:                }
        !           391: 
        !           392:                printf("  S_ST( '%c',\t%d,    %5u, %5u )%s /* %s */\n",
        !           393:                       sst[i].ch,
        !           394:                       sst[i].followedby,
        !           395:                       sst[i].match_next_s,
        !           396:                       sst[i].other_next_s,
        !           397:                       (i + 1 < sst_highwater)
        !           398:                           ? ","
        !           399:                           : " ",
        !           400:                       token_id_comment);
        !           401:        }
        !           402: 
        !           403:        printf("};\n\n");
        !           404: }
        !           405: 
        !           406: 
        !           407: /* Define a function to create the states of the scanner. This function
        !           408:  * is used by the create_keyword_scanner function below.
        !           409:  *
        !           410:  * This function takes a suffix of a keyword, the token to be returned on
        !           411:  * recognizing the complete keyword, and any pre-existing state that exists
        !           412:  * for some other keyword that has the same prefix as the current one.
        !           413:  */
        !           414: static int
        !           415: create_scan_states(
        !           416:        char *  text, 
        !           417:        int     token, 
        !           418:        follby  followedby,
        !           419:        int     prev_state
        !           420:        )
        !           421: {
        !           422:        int my_state;
        !           423:        int return_state;
        !           424:        int prev_char_s;
        !           425:        int curr_char_s;
        !           426: 
        !           427:        return_state = prev_state;
        !           428:        curr_char_s = prev_state;
        !           429:        prev_char_s = 0;
        !           430: 
        !           431:        /* Find the correct position to insert the state. 
        !           432:         * All states should be in alphabetical order
        !           433:         */
        !           434:        while (curr_char_s && (text[0] < sst[curr_char_s].ch)) {
        !           435:                prev_char_s = curr_char_s;
        !           436:                curr_char_s = sst[curr_char_s].other_next_s;
        !           437:        }
        !           438: 
        !           439:        /* 
        !           440:         * Check if a previously seen keyword has the same prefix as
        !           441:         * the current keyword.  If so, simply use the state for that
        !           442:         * keyword as my_state, otherwise, allocate a new state.
        !           443:         */
        !           444:        if (curr_char_s && (text[0] == sst[curr_char_s].ch)) {
        !           445:                my_state = curr_char_s;
        !           446:                if ('\0' == text[1]) {
        !           447:                        fprintf(stderr,
        !           448:                                "Duplicate entries for keyword '%s' in"
        !           449:                                " keyword_gen.c ntp_keywords[].\n",
        !           450:                                current_keyword);
        !           451:                        exit(2);
        !           452:                }
        !           453:        } else {
        !           454:                do
        !           455:                        my_state = sst_highwater++;
        !           456:                while (my_state < COUNTOF(sst)
        !           457:                       && sst[my_state].finishes_token);
        !           458:                if (my_state >= COUNTOF(sst)) {
        !           459:                        fprintf(stderr,
        !           460:                                "fatal, keyword scanner state array "
        !           461:                                "sst[%d] is too small, modify\n"
        !           462:                                "keyword-gen.c to increase.\n",
        !           463:                                (int)COUNTOF(sst));
        !           464:                        exit(3);
        !           465:                }
        !           466:                /* Store the next character of the keyword */
        !           467:                sst[my_state].ch = text[0]; 
        !           468:                sst[my_state].other_next_s = curr_char_s;
        !           469:                sst[my_state].followedby = FOLLBY_NON_ACCEPTING;
        !           470: 
        !           471:                if (prev_char_s)
        !           472:                        sst[prev_char_s].other_next_s = my_state;
        !           473:                else
        !           474:                        return_state = my_state;
        !           475:        }
        !           476: 
        !           477:        /* Check if the next character is '\0'.
        !           478:         * If yes, we are done with the recognition and this is an accepting
        !           479:         * state.
        !           480:         * If not, we need to continue scanning
        !           481:         */
        !           482:        if ('\0' == text[1]) {
        !           483:                sst[my_state].finishes_token = (u_short)token;
        !           484:                sst[my_state].followedby = (char)followedby;
        !           485: 
        !           486:                if (sst[token].finishes_token != (u_short)token) {
        !           487:                        fprintf(stderr,
        !           488:                                "fatal, sst[%d] not reserved for %s.\n",
        !           489:                                token, symbname(token));
        !           490:                        exit(6);
        !           491:                }
        !           492:                /* relocate so token id is sst[] index */
        !           493:                if (my_state != token) {
        !           494:                        sst[token] = sst[my_state];
        !           495:                        memset(&sst[my_state], 0,
        !           496:                               sizeof(sst[my_state]));
        !           497:                        do
        !           498:                                sst_highwater--;
        !           499:                        while (sst[sst_highwater].finishes_token);
        !           500:                        my_state = token;
        !           501:                        if (prev_char_s)
        !           502:                                sst[prev_char_s].other_next_s = my_state;
        !           503:                        else
        !           504:                                return_state = my_state;
        !           505:                }
        !           506:        } else
        !           507:                sst[my_state].match_next_s = 
        !           508:                    create_scan_states(
        !           509:                        &text[1],
        !           510:                        token,
        !           511:                        followedby,
        !           512:                        sst[my_state].match_next_s);
        !           513: 
        !           514:        return return_state;
        !           515: }
        !           516: 
        !           517: 
        !           518: /* Define a function that takes a list of (keyword, token) values and
        !           519:  * creates a keywords scanner out of it.
        !           520:  */
        !           521: 
        !           522: static int
        !           523: create_keyword_scanner(void)
        !           524: {
        !           525:        int scanner;
        !           526:        int i;
        !           527: 
        !           528:        sst_highwater = 1;      /* index 0 invalid, unused */
        !           529:        scanner = 0;
        !           530: 
        !           531:        for (i = 0; i < COUNTOF(ntp_keywords); i++) {
        !           532:                current_keyword = ntp_keywords[i].key;
        !           533:                scanner =
        !           534:                    create_scan_states(
        !           535:                        ntp_keywords[i].key, 
        !           536:                        ntp_keywords[i].token, 
        !           537:                        ntp_keywords[i].followedby,
        !           538:                        scanner);
        !           539:        }
        !           540: 
        !           541:        return scanner;
        !           542: }
        !           543: 
        !           544: 
        !           545: static void
        !           546: generate_token_text(void)
        !           547: {
        !           548:        int lowest_id;
        !           549:        int highest_id;
        !           550:        int id_count;
        !           551:        int id;
        !           552:        int i;
        !           553: 
        !           554:        /* sort ntp_keywords in token ID order */
        !           555:        qsort(ntp_keywords, COUNTOF(ntp_keywords),
        !           556:              sizeof(ntp_keywords[0]), compare_key_tok_id);
        !           557: 
        !           558:        lowest_id = ntp_keywords[0].token;
        !           559:        highest_id = ntp_keywords[COUNTOF(ntp_keywords) - 1].token;
        !           560:        id_count = highest_id - lowest_id + 1;
        !           561: 
        !           562:        printf("#define LOWEST_KEYWORD_ID %d\n\n", lowest_id);
        !           563: 
        !           564:        printf("const char * const keyword_text[%d] = {", id_count);
        !           565: 
        !           566:        id = lowest_id;
        !           567:        i = 0;
        !           568:        while (i < COUNTOF(ntp_keywords)) {
        !           569:                while (id < ntp_keywords[i].token) {
        !           570:                        printf(",\n\t/* %-5d %5d %20s */\tNULL",
        !           571:                               id - lowest_id, id, symbname(id));
        !           572:                        id++;
        !           573:                }
        !           574:                if (i > 0)
        !           575:                        printf(",");
        !           576:                printf("\n\t/* %-5d %5d %20s */\t\"%s\"",
        !           577:                       id - lowest_id, id, symbname(id), 
        !           578:                       ntp_keywords[i].key);
        !           579:                i++;
        !           580:                id++;
        !           581:        }
        !           582: 
        !           583:        printf("\n};\n\n");
        !           584: }
        !           585: 
        !           586:        
        !           587: int
        !           588: compare_key_tok_id(
        !           589:        QSORTP a1,
        !           590:        QSORTP a2
        !           591:        )
        !           592: {
        !           593:        const struct key_tok *p1 = (const void *)a1;
        !           594:        const struct key_tok *p2 = (const void *)a2;
        !           595: 
        !           596:        if (p1->token == p2->token)
        !           597:                return 0;
        !           598: 
        !           599:        if (p1->token < p2->token)
        !           600:                return -1;
        !           601:        else
        !           602:                return 1;
        !           603: }
        !           604: 
        !           605: 
        !           606: int
        !           607: compare_key_tok_text(
        !           608:        QSORTP a1,
        !           609:        QSORTP a2
        !           610:        )
        !           611: {
        !           612:        const struct key_tok *p1 = (const void *)a1;
        !           613:        const struct key_tok *p2 = (const void *)a2;
        !           614: 
        !           615:        return strcmp(p1->key, p2->key);
        !           616: }
        !           617: 
        !           618: 
        !           619: /*
        !           620:  * populate_symb() - populate symb[] lookup array with symbolic token
        !           621:  *                  names such that symb[T_Age] == "T_Age", etc.
        !           622:  */
        !           623: void
        !           624: populate_symb(
        !           625:        char *header_file
        !           626:        )
        !           627: {
        !           628:        FILE *  yh;
        !           629:        char    line[128];
        !           630:        char    name[128];
        !           631:        int     token;
        !           632: 
        !           633:        yh = fopen(header_file, "r");
        !           634:        if (NULL == yh) {
        !           635:                perror("unable to open yacc/bison header file");
        !           636:                exit(4);
        !           637:        }
        !           638: 
        !           639:        while (NULL != fgets(line, sizeof(line), yh))
        !           640:                if (2 == sscanf(line, "#define %s %d", name, &token)
        !           641:                    && 'T' == name[0] && '_' == name[1] && token >= 0
        !           642:                    && token < COUNTOF(symb))
        !           643: 
        !           644:                        symb[token] = estrdup(name);
        !           645: 
        !           646:        fclose(yh);
        !           647: }
        !           648: 
        !           649: 
        !           650: const char *
        !           651: symbname(
        !           652:        int token
        !           653:        )
        !           654: {
        !           655:        char *name;
        !           656: 
        !           657:        if (token >= 0 && token < COUNTOF(symb) && symb[token] != NULL)
        !           658:                return symb[token];
        !           659: 
        !           660:        LIB_GETBUF(name);
        !           661:        snprintf(name, LIB_BUFLENGTH, "%d", token);
        !           662:        return name;
        !           663: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>