Mercurial > ~dholland > hg > ag > index.cgi
view cgbigen/cgbigen.syn @ 7:57b2cc9b87f7
Use memcpy instead of strncpy when we know the length anyway.
Modern gcc seems to think it knows how to detect misuse of strncpy,
but it's wrong (in fact: very, very wrong) and the path of least
resistance is to not try to fight with it.
author | David A. Holland |
---|---|
date | Mon, 30 May 2022 23:47:52 -0400 |
parents | 13d2b8934445 |
children |
line wrap: on
line source
{ /* * AnaGram, a System for Syntax Directed Programming * Copyright 1993 Parsifal Software. All Rights Reserved. * Copyright 2006 David A. Holland. All Rights Reserved. * See the file COPYING for license and usage terms. * * cgbigen.syn - Syntax for CG source file (cg46.cgs) * Generates cg46.h. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <assert.h> } { static FILE *infile, *outfile; #define GET_INPUT ((PCB).input_code = getc(infile)) #define TEMPFILE ".cgstemp" ////////////////////////////// #define STRBUFSIZE 32768 static char strbuf[STRBUFSIZE]; static size_t strbufpos = 0; static void addstr(int ch) { if (strbufpos >= sizeof(strbuf)) { fprintf(stderr, "compile-cgs: string buffer overflow; make it larger\n"); exit(1); } strbuf[strbufpos++] = ch; } static const char *getstr(void) { addstr(0); strbufpos = 0; return strbuf; } ////////////////////////////// /* remove a character from strbuf[] */ static void strsnip(size_t pos) { assert(pos < strbufpos); strbufpos--; memmove(strbuf+pos, strbuf+pos+1, strbufpos); } /* munge newlines in strbuf[]. for exact regression test compliance. */ static void fudgenewlines(void) { while (strbufpos > 0 && strbuf[0] == '\n') { strsnip(0); } while (strbufpos > 1 && strbuf[strbufpos-1] == '\n' && strbuf[strbufpos-2] == '\n') { strbufpos--; } } ////////////////////////////// static void emitstring(const char *s) { size_t i, len; unsigned pos = 0; len = strlen(s); if (len==0) { fprintf(outfile, " \"\"\n"); return; } for (i=0; i<len; i++) { if (pos==0) { fprintf(outfile, " \""); } switch (s[i]) { case '\r': if (pos==0) pos++; continue; case '\n': fputs("\\n", outfile); pos+=3; break; case '?': fputs("\\077", outfile); pos+=4; break; case '"': fputs("\\\"", outfile); pos+=4; break; case '\\': fputs("\\\\", outfile); pos+=4; break; default: if (s[i]>=32 && s[i]<127) { fputc(s[i], outfile); pos++; } else { fprintf(outfile, "\\%03o", (unsigned)(unsigned char)s[i]); pos+=4; } break; } if (pos>=72) { fprintf(outfile, "\"\n"); pos = 0; } } if (pos>0) { fprintf(outfile, "\"\n"); } } ////////////////////////////// static unsigned bodynum = 0, titlenum = 0; static int havetitle = 0; static void emitbody(const char *s) { unsigned num; num = bodynum; bodynum = titlenum; havetitle = 0; fprintf(outfile, "static const char cgbody_%u[] =\n", num); emitstring(s); fprintf(outfile, ";\n"); } static void emittitle(const char *s) { unsigned num; num = titlenum++; if (havetitle) { fprintf(outfile, "#define cgbody_%u cgbody_%u\n", num, bodynum); } else { havetitle = 1; } fprintf(outfile, "static const char cgtitle_%u[] =\n", num); emitstring(s); fprintf(outfile, ";\n"); } static void emittable(void) { unsigned i; assert(bodynum == titlenum); fprintf(outfile, "struct cgentry {\n"); fprintf(outfile, " const char *name;\n"); fprintf(outfile, " const char *data;\n"); fprintf(outfile, "};\n\n"); fprintf(outfile, "static const unsigned cgtablenum = %u;\n", bodynum); fprintf(outfile, "static struct cgentry cgtable[%u] = {\n", bodynum); for (i=0; i<bodynum; i++) { fprintf(outfile, " { cgtitle_%u, cgbody_%u },\n", i, i); } fprintf(outfile, "};\n\n"); } ////////////////////////////// static void compile(const char *inpath, const char *outpath) { infile = fopen(inpath, "rt"); if (!infile) { fprintf(stderr, "compile-cgs: %s: %s\n", inpath, strerror(errno)); exit(1); } outfile = fopen(TEMPFILE, "wt"); if (!outfile) { fprintf(stderr, "compile-cgs: %s: %s\n", TEMPFILE, strerror(errno)); exit(1); } fprintf(outfile, "/* Automatically generated; do not edit */\n\n"); cgbigen(); if (PCB.exit_flag != AG_SUCCESS_CODE) { exit(1); } emittable(); fclose(outfile); fclose(infile); rename(TEMPFILE, outpath); } int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: compile-cgs input-file output-file\n"); exit(1); } compile(argv[1], argv[2]); return 0; } } [ default token type = void //error trace line numbers line numbers path = "cgbigen.syn" ] eof = -1 range = 0..255 blank = ' ' + '\t' cr = '\r' nl = '\n' textchar = range - cr - nl namechar = textchar - blank - ';' - ',' ////////////////////////////// (void) file $ -> blank lines?, block..., eof (void) block -> title line, body line?..., "##", blank lines? = fudgenewlines(), emitbody(getstr()); (void) title line -> titles, comment?, newline ////////////////////////////// (void) titles -> title -> titles, ',', blank?..., [comment?, newline, blank?...], title (void) title -> name, blank?... = emittitle(getstr()); (void) name -> namechar:c = addstr(c); -> name, namechar:c = addstr(c); -> name, blank..., namechar:c = addstr(' '), addstr(c); ////////////////////////////// (void) body line -> newline = addstr('\n'); -> text, newline = addstr('\n'); (void) text -> textchar:c = addstr(c); -> text, textchar:c = addstr(c); ////////////////////////////// (void) comment -> {';' | "//"}, textchar... (void) newline -> cr?, nl (void) blank lines -> blank line... (void) blank line -> blank?..., newline