/*
* bnf.c - program entry and compiler body
*
* Original created: Fri Sep 17 23:51:38 1993
*
* Copyright (C) 1993 B.J. van der Weerd
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* $Id: bnf.c,v 1.4 2002/11/28 21:14:07 bsod Exp $
*
***
*
* $Log: bnf.c,v $
* Revision 1.4 2002/11/28 21:14:07 bsod
* Added --tabsize option and added the calc.bnf example. also added the '%%' syntax
* to the bnf grammar.
*
* Revision 1.1 2001/06/20 05:39:34 bsod
* imported bnf program that is originally written at the UU some while ago now:P
*
* Revision 1.15 1998/03/17 18:21:59 bjweerd
* first Linux version
*
* Revision 1.13 1993/09/30 06:16:01 dim
* Ported the code to GNU gcc compiler. All functions are declared more
* C-friendly, like return int explicitly. also deleted the gnulib/gnulib.lib
* dependency, ALL source is compiled by C.
*
* Revision 1.12 93/09/29 22:33:35 bjweerd
* Again... a lot of changes.. The input grammar is now complete,
* for now there won't be any changes in the BNF grammar, but
* in the output only. Added a little bit more friendly commandline
* interface. 'bnf.c' was completely revised.
*
* Revision 1.11 93/09/28 22:42:52 bjweerd
* Fixed a LOT of bugs, leaving with a LOT of bugs:(
*
* Revision 1.9 93/09/28 14:04:08 bjweerd
* Finaly fixed the bug that caused comments to be parsed incorrectly!
* The bug was that 'isprint' is a macro, expanding a function call twice...
* a function with side effects:(
*
* Revision 1.8 93/09/27 22:49:42 H19
* Changed a lot, Comments now start with the '%' char because the
* '#' char is ambigous now
*
* Revision 1.7 93/09/20 14:50:21 bjweerd
* The operator '#' is now parsed correctly, and does generate some CODE!
*
* Revision 1.6 93/09/19 22:29:51 bjweerd
* some cleaning up again... *sigh*
*
* Revision 1.5 1993/09/19 21:05:10 bjweerd
* General name clean-up. All public names (as they appear in the map
* file generated by the linker now start with '__BNF_'.
* Builtin functions are now documented in the manual. Added FSF licence
* in the generated parsers. Changes in the syntax:
* - error( <string> ) is now available, added the '#' operator,
* but currently there is no correct output for this operator, so
* DONT use it:)
*
* Revision 1.2 1993/09/19 18:21:13 bjweerd
* Added GNU getopt, changed I/O grammar for the BNF with an elegant change:
* in('..') -> '...'
* out('...') -> `...`
* trans('...') -> "..."
* '.' means trans_char.
*
* Revision 1.1 1993/09/18 13:59:38 bjweerd
* Initial revision
*
*
* --------------------------------------------------------------------
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "getopt.h"
#ifdef _WIN32
# include <io.h>
#else
# include <unistd.h>
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "../version.h"
#if defined( __GNUC__ ) && !defined( EXIT_SUCCESS )
# define EXIT_SUCCESS 0
# define EXIT_FAILURE (!EXIT_SUCCESS)
#endif
/* these provide some diagnostics in case of error (and success) */
extern unsigned __BNF_err_line;
extern unsigned long __BNF_no_read, __BNF_no_written;
extern unsigned int __BNF_tabsize;
/* we have either a strings or files as input and output */
int __BNF_str_io_parser(char* input,char* output,int (*syntax)());
int __BNF_fil_io_parser(FILE* input,FILE* output,int (*syntax)());
/* these select file or string io automatically */
int __BNF_put(int ch);
int __BNF_get(void);
int __BNF_flush(void);
/* This procedure will lowercase a filename and convert '\\' to '/' */
extern char *program_name;
char *neat_fname( char *fname );
extern int grammar( void ); /* parser entry point */
extern FILE *if_ptr, *of_ptr;
/*
* public data
*/
char
*program_name, /* --- program's file name */
*__BNF_infname, /* --- filename being compiled */
*src_lang = "bnf", /* --- default extension of source files */
*dest_lang = "c", /* --- default extension of target files */
*g_outfname = NULL; /* --- points to an explicitly specified
output filename */
int
textmode = 1, /* --- true if files are opened in textmode */
verbose = 0, /* --- true if verbose mode is specified */
debug = 0; /* --- true if debug mode is specified */
unsigned
no_errors, /* --- number of errors encountered */
max_errors = 15; /* --- default number of errors printed */
/*
* functions
*/
char *cat_fname( char *fname, char *ext, int override )
{
char *s, tmp[32];
for ( s = fname; *s; s++ )
if ( *s == '\\' ) *s = '/';
do {
if ( *--s == '.' ) {
if ( override ) {
/* The input file cannot have the extension of the
* output language, for obvious safety reasons */
if( strcmp( (s+1), (strcpy( tmp, ext )) ) == 0 )
return NULL;
}
strcpy( s+1, ext );
return fname;
}
} while ( s != fname && *s != '/');
strcat( fname, "." );
strcat( fname, ext );
return fname;
}
int compiler_body( char *fname )
{
static char *stdin_fname = "<stdin>", *stdout_fname = "<stdout>";
char *infname = stdin_fname, *outfname = stdout_fname;
char if_buf[128], of_buf[128];
FILE *if_ptr=stdin, *of_ptr=stdout;
int retval;
/* --- open the input and ouput files --- */
if ( fname ) {
if ( (infname = cat_fname( strcpy( if_buf, fname ),
src_lang, 0)) == NULL ||
(outfname = cat_fname( strcpy( of_buf, fname ),
dest_lang, 1 )) == NULL )
{
fprintf( stderr, "Fatal: Same name '%s' for input and output file.\n", fname );
return 1;
}
if ( (if_ptr = fopen( infname , textmode ? "r":"rb" )) == NULL ) {
fprintf( stderr, "Fatal: Cannot open '%s' for reading: %s",
infname, strerror( errno ) );
return 1;
}
if ( g_outfname ) outfname = g_outfname;
if ( outfname &&
(of_ptr = fopen( outfname, textmode ? "w":"wb" )) == NULL )
{
fprintf( stderr, "Fatal: Cannot open '%s' for writing: %s",
outfname, strerror( errno ) );
fclose( if_ptr );
return 1;
}
}
if ( debug )
fprintf( stderr, "[Input(%s) = '%s', Output(%s) = '%s']\n",
textmode ? "r":"rb", infname, textmode ? "w":"wb", outfname );
__BNF_infname = infname;
no_errors = 0;
if ( verbose )
fprintf( stderr, "%s: ", infname );
retval = __BNF_fil_io_parser( if_ptr, of_ptr, grammar);
if ( no_errors ) retval = 1;
if ( verbose )
fprintf( stderr, "%lu bytes read, %lu bytes written.\n",
__BNF_no_read, __BNF_no_written );
/* Close the input and output */
if ( *outfname != '<' ) {
fclose( if_ptr );
/* delete output file if there was no output AND is zero-length */
if ( __BNF_no_written == 0 || retval ) {
fclose( of_ptr );
if ( debug )
fprintf( stderr,"[Deleting file: '%s']\n", outfname );
unlink( outfname );
}
else
fclose( of_ptr );
}
return retval;
}
void option_copying(void)
{
fprintf( stderr,
"This is free software; you can redistribute it and/or modify it\n"
"under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation. See the file COPYING for details.\n\n"
"This program is distributed in the hope that it will be useful, but\n"
"WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
);
}
void option_help(void)
{
printf("Usage: " PKG_NAME " [OPTION]... [FILE]\n"
"Generates a plain \"C\" parser for the input BNF grammar\n"
"\n"
" -o, --output=FILE set output filename to FILE\n"
" -t, --tabsize=NUM replace tabs with NUM spaces in the parser\n"
" -b, --binary binary file mode (text is default)\n"
" -v, --verbose be verbose\n"
" -d, --debug debug mode (not recommended)\n"
" -c, --copying display legal terms\n"
" --help display this help and exit\n"
" --version output version information and exit\n"
"\n"
"You can also use <stdin> and <stdout> which makes " PKG_NAME " usable\n"
"within pipes.\n"
"\n"
"Please report bugs to <bsod@springbank.echomania.com>.\n"
);
fflush(stdout);
}
void option_show_version(void)
{
printf("%s %s\n", PKG_NAME, PKG_VERSION);
printf("\n"
"Copyright (C) 2002 Han Leusheus and Bert van der Weerd\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
);
fflush(stdout);
}
int
main(int argc, char *argv[])
{
int option_index = 0, c;
static char *getopt_str = "cdbhHo:svVt:";
static struct option long_options[] =
{
{"copying", 0, 0, 'c'},
{"debug", 0, 0, 'd'},
{"binary", 0, 0, 'b'},
{"help", 0, 0, 'h'},
{"output", 1, 0, 'o'},
{"verbose", 0, 0, 'v'},
{"version", 0, 0, 'V'},
{"tabsize", 1, 0, 't'},
{0, 0, 0, 0}
};
/* --- Initialize the program name (if under DOS) --- */
program_name = neat_fname( argv[0] );
if_ptr = stdin;
of_ptr = stdout;
/* --- parse the options --- */
while ( (c = getopt_long( argc, argv,
getopt_str, long_options, &option_index )) != EOF )
{
switch ( c ) {
case 'c': /* copying */
option_copying();
return 0;
case 'd': /* debug */
debug = !debug;
break;
case 'b': /* filemode */
textmode = !textmode;
break;
case 'H': /* help */
case 'h':
option_help();
return 0;
case 'o': /* output */
if ( debug ) fprintf( stderr, "[-o %s]\n", optarg );
g_outfname = optarg;
break;
case 'v': /* verbose */
verbose = !verbose;
break;
case 'V': /* version info */
option_show_version();
return 0;
case 't':
__BNF_tabsize = atoi(optarg);
if (__BNF_tabsize < 1) {
fprintf(stderr,"%s: invalid tabsize `%s'\n",argv[0],optarg);
return 1;
}
case '?':
break;
default:
fprintf(stderr,
"getopt() returned invalid character `%c'.",
c);
}
}
/* --- filenames to compile --- */
if ( optind < argc ) {
while ( optind < argc ) {
if ( compiler_body( argv[optind++] ) )
return EXIT_FAILURE;
}
}
else if ( !isatty( fileno( stdin ) ) ) {
if ( !textmode ) {
assert(1+1 == 1);
/*setmode( fileno( stdin ), O_BINARY );
setmode( fileno( stdout ), O_BINARY ); */
}
return compiler_body( NULL ) ? EXIT_FAILURE : EXIT_SUCCESS;
}
else {
option_help();
}
return EXIT_SUCCESS;
}
void user_error( char *message )
{
if ( ++no_errors <= max_errors ) {
fprintf( stderr, "error %s %d: %s.\n",
__BNF_infname, __BNF_err_line, message );
}
}
char *neat_fname( char *fname )
{
return fname;
}
/* eof */
syntax highlighted by Code2HTML, v. 0.9.1