Files

231 lines
6.7 KiB
C++

/* P E R P L E X . C
* BRL-CAD
*
* Copyright (c) 2011-2021 United States Government as represented by
* the U.S. Army Research Laboratory.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @file perplex.c
*
* perplex scanner-generator
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "perplex.h"
#include "mbo_getopt.h"
/*
Desired Features:
- string and file inputs w/ autobuffering
- autogenerate scanner function
- indicate end-of-input by returning -1
- if rule actions don't end with a return,
ignore the recognized token and continue parsing
- character classes (might implement using auto-included named patterns)
- include C code (re2c passes through by default)
- error mechanism ? (reentrancy?)
- start conditions, and condition blocks in particular
- unquoted literal characters
- echo unmatched text?
- yylineno? (reentrancy?)
Possible Options (borrowed from flex usage message):
-?
-h, --help produce this help message
--header-file=FILE create a C header file in addition to the scanner
-L, --noline suppress #line directives in scanner
-o, --outfile=FILE specify output filename (stdout by default?)
-P, --prefix=STRING use STRING as prefix instead of "yy"
-t, --template=FILE specify path to scanner template file
-v, --version report perplex version
--yylineno track line count in yylineno
*/
using namespace re2c;
static const mbo_opt_struct options[] =
{
mbo_opt_struct('?', 0, "help"),
mbo_opt_struct('h', 0, "help"),
mbo_opt_struct('c', 0, "conditions"),
mbo_opt_struct('i', 1, "header"),
mbo_opt_struct('o', 1, "output"),
mbo_opt_struct('s', 0, "safe-mode"),
mbo_opt_struct('t', 1, "template"),
mbo_opt_struct('v', 0, "version"),
mbo_opt_struct('-', 0, NULL)
};
static const char version[] = "1.0.1";
static const char usage[] =
"Usage: perplex [options] input\n"
" -?\n"
" -h, --help\t\tprints this message\n"
" -c, --conditions\tenable support for start conditions\n"
" -i, --header PATH\tspecify path of header file\n"
" -o, --output\t\tspecify path of output file\n"
" -s, --safe-mode\tprevent rule fall-through by skipping matched text by default\n"
" -t, --template PATH\tspecify path to scanner template file\n"
" -v, --version\t\tprint perplex version number and exit\n"
;
int main(int argc, char *argv[])
{
int c;
int tokenID;
int opt_ind = 1;
char *opt_arg = NULL;
void *parser;
perplex_t scanner;
appData_t *appData;
char defaultTemplate[] = "perplex_template.c";
FILE *inFile;
FILE *outFile = stdout;
FILE *templateFile = NULL;
FILE *headerFile = NULL;
int usingConditions = 0;
int safeMode = 0;
if (argc < 2) {
puts(usage);
return 0;
}
while ((c = mbo_getopt(argc, argv, options, &opt_arg, &opt_ind, 0)) != -1) {
switch (c) {
case '?':
case 'h':
puts(usage);
return 0;
case 'c':
usingConditions = 1;
break;
case 'i':
if (opt_arg == NULL) {
fprintf(stderr, "Error: Header option requires file-path argument.\n");
exit(1);
}
if ((headerFile = fopen(opt_arg, "w")) == NULL) {
fprintf(stderr, "Error: Couldn't open \"%s\" for writing.\n", opt_arg);
exit(1);
}
break;
case 'o':
if (opt_arg == NULL) {
fprintf(stderr, "Error: Output option requires file-path argument.\n");
exit(1);
}
if ((outFile = fopen(opt_arg, "w")) == NULL) {
fprintf(stderr, "Error: Couldn't open \"%s\" for writing.\n", opt_arg);
exit(1);
}
break;
case 's':
safeMode = 1;
break;
case 't':
if (opt_arg == NULL) {
fprintf(stderr, "Error: Template option requires file-path argument.\n");
exit(1);
}
if ((templateFile = fopen(opt_arg, "r")) == NULL) {
fprintf(stderr, "Error: Couldn't open \"%s\" for reading.\n", opt_arg);
exit(1);
}
break;
case 'v':
puts(version);
exit(0);
default:
fprintf(stderr, "Error: Error in option string.\n");
puts(usage);
exit(1);
}
}
/* look for default if scanner template not specified */
if (templateFile == NULL) {
if ((templateFile = fopen(defaultTemplate, "r")) == NULL) {
fprintf(stderr, "Error: Couldn't open default template \"%s\" "
"for reading.\n\tSpecify template file using \"-t PATH\" "
"option.\n", defaultTemplate);
exit(1);
}
}
if ((inFile = fopen(argv[opt_ind], "r")) == NULL) {
fprintf(stderr, "Error: couldn't open input \"%s\" for reading\n", argv[opt_ind]);
exit(1);
}
/* create scanner and parser */
scanner = perplexFileScanner(inFile);
parser = ParseAlloc(malloc);
scanner->appData = static_cast<appData_t*>(malloc(sizeof(appData_t)));
appData = scanner->appData;
appData->in = inFile;
appData->out = outFile;
appData->header = headerFile;
appData->scanner_template = templateFile;
appData->safeMode = safeMode;
appData->usingConditions = usingConditions;
appData->conditions = (char*)NULL;
/* parse */
while ((tokenID = yylex(scanner)) != YYEOF) {
Parse(parser, tokenID, appData->tokenData, appData);
}
Parse(parser, 0, appData->tokenData, appData);
fclose(inFile);
fclose(outFile);
free(appData);
ParseFree(parser, free);
perplexFree(scanner);
return 0;
}
// Local Variables:
// tab-width: 8
// mode: C++
// c-basic-offset: 4
// indent-tabs-mode: t
// c-file-style: "stroustrup"
// End:
// ex: shiftwidth=4 tabstop=8