147132Sbostic /*-
260698Sbostic * Copyright (c) 1991, 1993
360698Sbostic * The Regents of the University of California. All rights reserved.
447132Sbostic *
547132Sbostic * This code is derived from software contributed to Berkeley by
647132Sbostic * Kenneth Almquist.
747132Sbostic *
847132Sbostic * %sccs.include.redist.c%
947132Sbostic */
1047132Sbostic
1147132Sbostic #ifndef lint
1260698Sbostic static char copyright[] =
1360698Sbostic "@(#) Copyright (c) 1991, 1993\n\
1460698Sbostic The Regents of the University of California. All rights reserved.\n";
1547132Sbostic #endif /* not lint */
1647132Sbostic
1747132Sbostic #ifndef lint
18*69272Schristos static char sccsid[] = "@(#)mksyntax.c 8.2 (Berkeley) 05/04/95";
1947132Sbostic #endif /* not lint */
2047132Sbostic
2147132Sbostic /*
2247132Sbostic * This program creates syntax.h and syntax.c.
2347132Sbostic */
2447132Sbostic
2547132Sbostic #include <stdio.h>
26*69272Schristos #include <string.h>
2747132Sbostic #include "parser.h"
2847132Sbostic
2947132Sbostic
3047132Sbostic struct synclass {
3147132Sbostic char *name;
3247132Sbostic char *comment;
3347132Sbostic };
3447132Sbostic
3547132Sbostic /* Syntax classes */
3647132Sbostic struct synclass synclass[] = {
37*69272Schristos { "CWORD", "character is nothing special" },
38*69272Schristos { "CNL", "newline character" },
39*69272Schristos { "CBACK", "a backslash character" },
40*69272Schristos { "CSQUOTE", "single quote" },
41*69272Schristos { "CDQUOTE", "double quote" },
42*69272Schristos { "CENDQUOTE", "a terminating quote" },
43*69272Schristos { "CBQUOTE", "backwards single quote" },
44*69272Schristos { "CVAR", "a dollar sign" },
45*69272Schristos { "CENDVAR", "a '}' character" },
46*69272Schristos { "CLP", "a left paren in arithmetic" },
47*69272Schristos { "CRP", "a right paren in arithmetic" },
48*69272Schristos { "CEOF", "end of file" },
49*69272Schristos { "CCTL", "like CWORD, except it must be escaped" },
50*69272Schristos { "CSPCL", "these terminate a word" },
51*69272Schristos { NULL, NULL }
5247132Sbostic };
5347132Sbostic
5447132Sbostic
5547132Sbostic /*
5647132Sbostic * Syntax classes for is_ functions. Warning: if you add new classes
5747132Sbostic * you may have to change the definition of the is_in_name macro.
5847132Sbostic */
5947132Sbostic struct synclass is_entry[] = {
60*69272Schristos { "ISDIGIT", "a digit" },
61*69272Schristos { "ISUPPER", "an upper case letter" },
62*69272Schristos { "ISLOWER", "a lower case letter" },
63*69272Schristos { "ISUNDER", "an underscore" },
64*69272Schristos { "ISSPECL", "the name of a special parameter" },
65*69272Schristos { NULL, NULL }
6647132Sbostic };
6747132Sbostic
68*69272Schristos static char writer[] = "\
6947132Sbostic /*\n\
7047132Sbostic * This file was generated by the mksyntax program.\n\
7147132Sbostic */\n\
7247132Sbostic \n";
7347132Sbostic
7447132Sbostic
75*69272Schristos static FILE *cfile;
76*69272Schristos static FILE *hfile;
77*69272Schristos static char *syntax[513];
78*69272Schristos static int base;
79*69272Schristos static int size; /* number of values which a char variable can have */
80*69272Schristos static int nbits; /* number of bits in a character */
81*69272Schristos static int digit_contig;/* true if digits are contiguous */
8247132Sbostic
83*69272Schristos static void filltable __P((char *));
84*69272Schristos static void init __P((void));
85*69272Schristos static void add __P((char *, char *));
86*69272Schristos static void print __P((char *));
87*69272Schristos static void output_type_macros __P((void));
88*69272Schristos static void digit_convert __P((void));
8947132Sbostic
90*69272Schristos int
main(argc,argv)91*69272Schristos main(argc, argv)
92*69272Schristos int argc;
93*69272Schristos char **argv;
94*69272Schristos {
9547132Sbostic char c;
9647132Sbostic char d;
9747132Sbostic int sign;
9847132Sbostic int i;
9947132Sbostic char buf[80];
10047132Sbostic int pos;
10147132Sbostic static char digit[] = "0123456789";
10247132Sbostic
10347132Sbostic /* Create output files */
10447132Sbostic if ((cfile = fopen("syntax.c", "w")) == NULL) {
10547132Sbostic perror("syntax.c");
10647132Sbostic exit(2);
10747132Sbostic }
10847132Sbostic if ((hfile = fopen("syntax.h", "w")) == NULL) {
10947132Sbostic perror("syntax.h");
11047132Sbostic exit(2);
11147132Sbostic }
11247132Sbostic fputs(writer, hfile);
11347132Sbostic fputs(writer, cfile);
11447132Sbostic
11547132Sbostic /* Determine the characteristics of chars. */
11647132Sbostic c = -1;
11747132Sbostic if (c < 0)
11847132Sbostic sign = 1;
11947132Sbostic else
12047132Sbostic sign = 0;
12147132Sbostic for (nbits = 1 ; ; nbits++) {
12247132Sbostic d = (1 << nbits) - 1;
12347132Sbostic if (d == c)
12447132Sbostic break;
12547132Sbostic }
12647132Sbostic printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits);
12747132Sbostic if (nbits > 9) {
12847132Sbostic fputs("Characters can't have more than 9 bits\n", stderr);
12947132Sbostic exit(2);
13047132Sbostic }
13147132Sbostic size = (1 << nbits) + 1;
13247132Sbostic base = 1;
13347132Sbostic if (sign)
13447132Sbostic base += 1 << (nbits - 1);
13547132Sbostic digit_contig = 1;
13647132Sbostic for (i = 0 ; i < 10 ; i++) {
13747132Sbostic if (digit[i] != '0' + i)
13847132Sbostic digit_contig = 0;
13947132Sbostic }
14047132Sbostic
14147166Sbostic fputs("#include <sys/cdefs.h>\n", hfile);
14247166Sbostic
14347132Sbostic /* Generate the #define statements in the header file */
14447132Sbostic fputs("/* Syntax classes */\n", hfile);
14547132Sbostic for (i = 0 ; synclass[i].name ; i++) {
14647132Sbostic sprintf(buf, "#define %s %d", synclass[i].name, i);
14747132Sbostic fputs(buf, hfile);
148*69272Schristos for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
14947132Sbostic putc('\t', hfile);
15047132Sbostic fprintf(hfile, "/* %s */\n", synclass[i].comment);
15147132Sbostic }
15247132Sbostic putc('\n', hfile);
15347132Sbostic fputs("/* Syntax classes for is_ functions */\n", hfile);
15447132Sbostic for (i = 0 ; is_entry[i].name ; i++) {
15547132Sbostic sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
15647132Sbostic fputs(buf, hfile);
157*69272Schristos for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
15847132Sbostic putc('\t', hfile);
15947132Sbostic fprintf(hfile, "/* %s */\n", is_entry[i].comment);
16047132Sbostic }
16147132Sbostic putc('\n', hfile);
16247132Sbostic fprintf(hfile, "#define SYNBASE %d\n", base);
16347132Sbostic fprintf(hfile, "#define PEOF %d\n\n", -base);
16447132Sbostic putc('\n', hfile);
16547132Sbostic fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
16647132Sbostic fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
16747132Sbostic fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
16853301Smarc fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile);
16947132Sbostic putc('\n', hfile);
17047132Sbostic output_type_macros(); /* is_digit, etc. */
17147132Sbostic putc('\n', hfile);
17247132Sbostic
17347132Sbostic /* Generate the syntax tables. */
17447132Sbostic fputs("#include \"shell.h\"\n", cfile);
17547132Sbostic fputs("#include \"syntax.h\"\n\n", cfile);
17647132Sbostic init();
17747132Sbostic fputs("/* syntax table used when not in quotes */\n", cfile);
17847132Sbostic add("\n", "CNL");
17947132Sbostic add("\\", "CBACK");
18047132Sbostic add("'", "CSQUOTE");
18147132Sbostic add("\"", "CDQUOTE");
18247132Sbostic add("`", "CBQUOTE");
18347132Sbostic add("$", "CVAR");
18447132Sbostic add("}", "CENDVAR");
18547132Sbostic add("<>();&| \t", "CSPCL");
18647132Sbostic print("basesyntax");
18747132Sbostic init();
18847132Sbostic fputs("\n/* syntax table used when in double quotes */\n", cfile);
18947132Sbostic add("\n", "CNL");
19047132Sbostic add("\\", "CBACK");
19147132Sbostic add("\"", "CENDQUOTE");
19247132Sbostic add("`", "CBQUOTE");
19347132Sbostic add("$", "CVAR");
19447132Sbostic add("}", "CENDVAR");
195*69272Schristos /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
196*69272Schristos add("!*?[=~:/-", "CCTL");
19747132Sbostic print("dqsyntax");
19847132Sbostic init();
19947132Sbostic fputs("\n/* syntax table used when in single quotes */\n", cfile);
20047132Sbostic add("\n", "CNL");
20147132Sbostic add("'", "CENDQUOTE");
202*69272Schristos /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
203*69272Schristos add("!*?[=~:/-", "CCTL");
20447132Sbostic print("sqsyntax");
20553301Smarc init();
20653301Smarc fputs("\n/* syntax table used when in arithmetic */\n", cfile);
20753301Smarc add("\n", "CNL");
20853301Smarc add("\\", "CBACK");
20953301Smarc add("`", "CBQUOTE");
21053301Smarc add("'", "CSQUOTE");
21153301Smarc add("\"", "CDQUOTE");
21253301Smarc add("$", "CVAR");
21353301Smarc add("}", "CENDVAR");
21453301Smarc add("(", "CLP");
21553301Smarc add(")", "CRP");
21653301Smarc print("arisyntax");
21747132Sbostic filltable("0");
21847132Sbostic fputs("\n/* character classification table */\n", cfile);
21947132Sbostic add("0123456789", "ISDIGIT");
22047132Sbostic add("abcdefghijklmnopqrstucvwxyz", "ISLOWER");
22147132Sbostic add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER");
22247132Sbostic add("_", "ISUNDER");
22347132Sbostic add("#?$!-*@", "ISSPECL");
22447132Sbostic print("is_type");
22547132Sbostic if (! digit_contig)
22647132Sbostic digit_convert();
22747132Sbostic exit(0);
22847132Sbostic }
22947132Sbostic
23047132Sbostic
23147132Sbostic
23247132Sbostic /*
23347132Sbostic * Clear the syntax table.
23447132Sbostic */
23547132Sbostic
236*69272Schristos static void
filltable(dftval)23747132Sbostic filltable(dftval)
23847132Sbostic char *dftval;
239*69272Schristos {
24047132Sbostic int i;
24147132Sbostic
24247132Sbostic for (i = 0 ; i < size ; i++)
24347132Sbostic syntax[i] = dftval;
24447132Sbostic }
24547132Sbostic
24647132Sbostic
24747132Sbostic /*
24847132Sbostic * Initialize the syntax table with default values.
24947132Sbostic */
25047132Sbostic
251*69272Schristos static void
init()252*69272Schristos init()
253*69272Schristos {
25447132Sbostic filltable("CWORD");
25547132Sbostic syntax[0] = "CEOF";
25647132Sbostic syntax[base + CTLESC] = "CCTL";
25747132Sbostic syntax[base + CTLVAR] = "CCTL";
25847132Sbostic syntax[base + CTLENDVAR] = "CCTL";
25947132Sbostic syntax[base + CTLBACKQ] = "CCTL";
26047132Sbostic syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL";
26153301Smarc syntax[base + CTLARI] = "CCTL";
26253301Smarc syntax[base + CTLENDARI] = "CCTL";
26347132Sbostic }
26447132Sbostic
26547132Sbostic
26647132Sbostic /*
26747132Sbostic * Add entries to the syntax table.
26847132Sbostic */
26947132Sbostic
270*69272Schristos static void
add(p,type)27147132Sbostic add(p, type)
27247132Sbostic char *p, *type;
273*69272Schristos {
27447132Sbostic while (*p)
27547132Sbostic syntax[*p++ + base] = type;
27647132Sbostic }
27747132Sbostic
27847132Sbostic
27947132Sbostic
28047132Sbostic /*
28147132Sbostic * Output the syntax table.
28247132Sbostic */
28347132Sbostic
284*69272Schristos static void
print(name)28547132Sbostic print(name)
28647132Sbostic char *name;
287*69272Schristos {
28847132Sbostic int i;
28947132Sbostic int col;
29047132Sbostic
29147132Sbostic fprintf(hfile, "extern const char %s[];\n", name);
29247132Sbostic fprintf(cfile, "const char %s[%d] = {\n", name, size);
29347132Sbostic col = 0;
29447132Sbostic for (i = 0 ; i < size ; i++) {
29547132Sbostic if (i == 0) {
29647132Sbostic fputs(" ", cfile);
29747132Sbostic } else if ((i & 03) == 0) {
29847132Sbostic fputs(",\n ", cfile);
29947132Sbostic col = 0;
30047132Sbostic } else {
30147132Sbostic putc(',', cfile);
30247132Sbostic while (++col < 9 * (i & 03))
30347132Sbostic putc(' ', cfile);
30447132Sbostic }
30547132Sbostic fputs(syntax[i], cfile);
30647132Sbostic col += strlen(syntax[i]);
30747132Sbostic }
30847132Sbostic fputs("\n};\n", cfile);
30947132Sbostic }
31047132Sbostic
31147132Sbostic
31247132Sbostic
31347132Sbostic /*
31447132Sbostic * Output character classification macros (e.g. is_digit). If digits are
31547132Sbostic * contiguous, we can test for them quickly.
31647132Sbostic */
31747132Sbostic
318*69272Schristos static char *macro[] = {
31947132Sbostic "#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)",
32047132Sbostic "#define is_alpha(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER))",
32147132Sbostic "#define is_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER))",
32247132Sbostic "#define is_in_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))",
32347132Sbostic "#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))",
32447132Sbostic NULL
32547132Sbostic };
32647132Sbostic
327*69272Schristos static void
output_type_macros()328*69272Schristos output_type_macros()
329*69272Schristos {
33047132Sbostic char **pp;
33147132Sbostic
33247132Sbostic if (digit_contig)
33347132Sbostic macro[0] = "#define is_digit(c)\t((unsigned)((c) - '0') <= 9)";
33447132Sbostic for (pp = macro ; *pp ; pp++)
33547132Sbostic fprintf(hfile, "%s\n", *pp);
33647132Sbostic if (digit_contig)
33747132Sbostic fputs("#define digit_val(c)\t((c) - '0')\n", hfile);
33847132Sbostic else
33947132Sbostic fputs("#define digit_val(c)\t(digit_value[c])\n", hfile);
34047132Sbostic }
34147132Sbostic
34247132Sbostic
34347132Sbostic
34447132Sbostic /*
34547132Sbostic * Output digit conversion table (if digits are not contiguous).
34647132Sbostic */
34747132Sbostic
348*69272Schristos static void
digit_convert()349*69272Schristos digit_convert()
350*69272Schristos {
35147132Sbostic int maxdigit;
35247132Sbostic static char digit[] = "0123456789";
35347132Sbostic char *p;
35447132Sbostic int i;
35547132Sbostic
35647132Sbostic maxdigit = 0;
35747132Sbostic for (p = digit ; *p ; p++)
35847132Sbostic if (*p > maxdigit)
35947132Sbostic maxdigit = *p;
36047132Sbostic fputs("extern const char digit_value[];\n", hfile);
36147132Sbostic fputs("\n\nconst char digit_value[] = {\n", cfile);
36247132Sbostic for (i = 0 ; i <= maxdigit ; i++) {
36347132Sbostic for (p = digit ; *p && *p != i ; p++);
36447132Sbostic if (*p == '\0')
36547132Sbostic p = digit;
36647132Sbostic fprintf(cfile, " %d,\n", p - digit);
36747132Sbostic }
36847132Sbostic fputs("};\n", cfile);
36947132Sbostic }
370