mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-25 04:43:03 +01:00
2905 lines
70 KiB
C++
2905 lines
70 KiB
C++
//____________________________________________________________
|
|
//
|
|
// PROGRAM: Preprocessor
|
|
// MODULE: gpre.cpp
|
|
// DESCRIPTION: Main line routine
|
|
//
|
|
// The contents of this file are subject to the Interbase Public
|
|
// License Version 1.0 (the "License"); you may not use this file
|
|
// except in compliance with the License. You may obtain a copy
|
|
// of the License at http://www.Inprise.com/IPL.html
|
|
//
|
|
// Software distributed under the License is distributed on an
|
|
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
// or implied. See the License for the specific language governing
|
|
// rights and limitations under the License.
|
|
//
|
|
// The Original Code was created by Inprise Corporation
|
|
// and its predecessors. Portions created by Inprise Corporation are
|
|
// Copyright (C) Inprise Corporation.
|
|
//
|
|
// All Rights Reserved.
|
|
// Contributor(s): ______________________________________.
|
|
// $Id: gpre.cpp,v 1.65 2004-10-30 05:30:08 robocop Exp $
|
|
// Revision 1.2 2000/11/16 15:54:29 fsg
|
|
// Added new switch -verbose to gpre that will dump
|
|
// parsed lines to stderr
|
|
//
|
|
// Fixed gpre bug in handling row names in WHERE clauses
|
|
// that are reserved words now (DATE etc)
|
|
// (this caused gpre to dump core when parsing tan.e)
|
|
//
|
|
// Fixed gpre bug in handling lower case table aliases
|
|
// in WHERE clauses for sql dialect 2 and 3.
|
|
// (cause a core dump in a test case from C.R. Zamana)
|
|
//
|
|
// TMN (Mike Nordell) 11.APR.2001 - Reduce compiler warnings
|
|
//
|
|
// FSG (Frank Schlottmann-Gödde) 8.Mar.2002 - tiny cobol support
|
|
// fixed Bug No. 526204
|
|
//
|
|
// 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
|
|
//
|
|
//____________________________________________________________
|
|
//
|
|
//
|
|
|
|
#include "firebird.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "../gpre/gpre.h"
|
|
#include "../jrd/license.h"
|
|
#include "../jrd/intl.h"
|
|
#include "../gpre/cmp_proto.h"
|
|
#include "../gpre/hsh_proto.h"
|
|
#include "../gpre/gpre_proto.h"
|
|
#include "../gpre/lang_proto.h"
|
|
#include "../gpre/gpre_meta.h"
|
|
#include "../gpre/msc_proto.h"
|
|
#include "../gpre/par_proto.h"
|
|
#include "../jrd/gds_proto.h"
|
|
#include "../gpre/gpreswi.h"
|
|
#include "../common/utils_proto.h"
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef VMS
|
|
#include <descrip.h>
|
|
extern "C" {
|
|
int lib$get_foreign();
|
|
} // extern "C"
|
|
#endif
|
|
|
|
// Globals
|
|
GpreGlobals gpreGlob;
|
|
|
|
#ifdef SMALL_FILE_NAMES
|
|
const char* const SCRATCH = "fb_q";
|
|
#else
|
|
const char* const SCRATCH = "fb_query_";
|
|
#endif
|
|
|
|
const char* const FOPEN_READ_TYPE = "r";
|
|
const char* const FOPEN_WRITE_TYPE = "w";
|
|
|
|
static bool all_digits(const char*);
|
|
static bool arg_is_string(SLONG, TEXT**, const TEXT*);
|
|
static SSHORT compare_ASCII7z(const char*, const char*);
|
|
static SLONG compile_module(SLONG, const TEXT*);
|
|
static bool file_rename(TEXT*, const TEXT*, const TEXT*);
|
|
#ifdef GPRE_FORTRAN
|
|
static void finish_based(act*);
|
|
#endif
|
|
static int get_char(FILE*);
|
|
static bool get_switches(int, TEXT**, const in_sw_tab_t*, SW_TAB,
|
|
TEXT**);
|
|
static TOK get_token();
|
|
static int nextchar();
|
|
static SLONG pass1(const TEXT*);
|
|
static void pass2(SLONG);
|
|
static void print_switches();
|
|
static void remember_label(const TEXT*);
|
|
//static FILE* reposition_file(FILE *, SLONG);
|
|
static void return_char(SSHORT);
|
|
static SSHORT skip_white();
|
|
|
|
// Program wide globals
|
|
|
|
static FILE* input_file;
|
|
static FILE* trace_file;
|
|
static const TEXT* file_name;
|
|
static TEXT* out_file_name;
|
|
static SLONG position;
|
|
static SLONG last_position;
|
|
static SLONG line_position;
|
|
static SLONG first_position;
|
|
static SLONG prior_line_position;
|
|
|
|
static act* global_last_action;
|
|
static act* global_first_action;
|
|
static UCHAR classes[256];
|
|
|
|
static TEXT input_buffer[512], *input_char;
|
|
|
|
static DBB sw_databases;
|
|
// Added sw_verbose
|
|
// FSG 14.Nov.2000
|
|
static bool sw_verbose;
|
|
static bool sw_standard_out;
|
|
static USHORT sw_first;
|
|
static bool sw_lines;
|
|
static bool sw_trace;
|
|
static bool sw_alsys;
|
|
static int line_global;
|
|
static int warnings_global;
|
|
static int fatals_global;
|
|
|
|
//static jmp_buf fatal_env;
|
|
static const TEXT *comment_start, *comment_stop;
|
|
|
|
typedef void (*pfn_gen_routine) (const act*, int);
|
|
static pfn_gen_routine gen_routine;
|
|
|
|
static TEXT trace_file_name[128];
|
|
static SLONG traced_position = 0;
|
|
|
|
//___________________________________________________________________
|
|
// Test if input language is cpp based.
|
|
//
|
|
bool isLangCpp(LANG_T lang)
|
|
{
|
|
if (lang == lang_cxx || lang == lang_internal) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Type and table definition for the extension tables. Tells GPRE
|
|
* the default extensions for DML and host languages.
|
|
*/
|
|
|
|
struct ext_table_t
|
|
{
|
|
lang_t ext_language;
|
|
gpre_cmd_switch ext_in_sw;
|
|
const TEXT* in;
|
|
const TEXT* out;
|
|
};
|
|
|
|
|
|
static const ext_table_t dml_ext_table[] =
|
|
{
|
|
{ lang_c, IN_SW_GPRE_C, ".e", ".c" },
|
|
|
|
#ifndef VMS
|
|
#ifndef WIN_NT
|
|
{ lang_scxx, IN_SW_GPRE_SCXX, ".E", ".C" },
|
|
#endif
|
|
#endif
|
|
|
|
{ lang_cxx, IN_SW_GPRE_CXX, ".exx", ".cxx" },
|
|
{ lang_cpp, IN_SW_GPRE_CXX, ".epp", ".cpp" },
|
|
{ lang_internal, IN_SW_GPRE_G, ".e", ".c" },
|
|
{ lang_internal_cxx, IN_SW_GPRE_0, ".epp", ".cpp" },
|
|
{ lang_pascal, IN_SW_GPRE_P, ".epas", ".pas" },
|
|
|
|
#ifdef GPRE_FORTRAN
|
|
#ifdef VMS
|
|
{ lang_fortran, IN_SW_GPRE_F, ".efor", ".for" },
|
|
#else
|
|
{ lang_fortran, IN_SW_GPRE_F, ".ef", ".f" },
|
|
#endif
|
|
#endif // GPRE_FORTRAN
|
|
|
|
#ifdef GPRE_COBOL
|
|
#ifdef VMS
|
|
{ lang_cobol, IN_SW_GPRE_COB, ".ecob", ".cob" },
|
|
#else
|
|
{ lang_cobol, IN_SW_GPRE_COB, ".ecbl", ".cbl" },
|
|
#endif
|
|
#endif // GPRE_COBOL
|
|
|
|
#ifdef GPRE_ADA
|
|
#ifdef VMS
|
|
{ lang_ada, IN_SW_GPRE_ADA, ".eada", ".ada" },
|
|
#elif defined(hpux)
|
|
{ lang_ada, IN_SW_GPRE_ADA, ".eada", ".ada" },
|
|
#else
|
|
{ lang_ada, IN_SW_GPRE_ADA, ".ea", ".a" },
|
|
#endif
|
|
|
|
#ifdef ALSYS_ADA
|
|
{ lang_ada, IN_SW_GPRE_ALSYS, ".eada", ".ada" },
|
|
#endif
|
|
#endif // GPRE_ADA
|
|
|
|
#if (defined( WIN_NT))
|
|
{ lang_cplusplus, IN_SW_GPRE_CPLUSPLUS, ".epp", ".cpp" },
|
|
#else
|
|
{ lang_cplusplus, IN_SW_GPRE_CPLUSPLUS, ".exx", ".cxx" },
|
|
#endif
|
|
{ lang_undef, IN_SW_GPRE_0, NULL, NULL }
|
|
};
|
|
|
|
enum char_types {
|
|
CHR_LETTER = 1,
|
|
CHR_DIGIT = 2,
|
|
CHR_IDENT = 4,
|
|
CHR_QUOTE = 8,
|
|
CHR_WHITE = 16,
|
|
CHR_INTRODUCER = 32,
|
|
CHR_DBLQUOTE = 64
|
|
};
|
|
|
|
// macro compares chars; case sensitive for some platforms
|
|
|
|
#ifdef EITHER_CASE
|
|
#define SAME(p,q) UPPER7 (*p) == UPPER7 (*q)
|
|
#else
|
|
#define SAME(p,q) *p == *q
|
|
#endif
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Main line routine for C preprocessor. Initializes
|
|
// system, performs pass 1 and pass 2. Interprets
|
|
// command line.
|
|
//
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
gpre_sym* symbol;
|
|
int i;
|
|
TEXT* p;
|
|
TEXT spare_file_name[256];
|
|
TEXT spare_out_file_name[256];
|
|
bool renamed;
|
|
bool explicitt;
|
|
const ext_table_t* ext_tab;
|
|
sw_tab_t sw_table[IN_SW_GPRE_COUNT];
|
|
#ifdef VMS
|
|
FILE *temp;
|
|
TEXT temp_name[256];
|
|
SSHORT c;
|
|
#endif
|
|
|
|
gpreGlob.module_lc_ctype = NULL;
|
|
gpreGlob.errors_global = 0;
|
|
warnings_global = 0;
|
|
fatals_global = 0;
|
|
gpreGlob.ADA_create_database = 1;
|
|
|
|
bool use_lang_internal_gxx_output;
|
|
|
|
use_lang_internal_gxx_output = false;
|
|
strcpy(gpreGlob.ada_package, "");
|
|
gpreGlob.ada_flags = 0;
|
|
input_char = input_buffer;
|
|
|
|
#ifdef VMS
|
|
argc = VMS_parse(&argv, argc);
|
|
#endif
|
|
|
|
// Initialize character class table
|
|
for (i = 0; i <= 127; ++i) {
|
|
classes[i] = 0;
|
|
}
|
|
for (i = 128; i <= 255; ++i) {
|
|
classes[i] = CHR_LETTER | CHR_IDENT;
|
|
}
|
|
for (i = 'a'; i <= 'z'; ++i) {
|
|
classes[i] = CHR_LETTER | CHR_IDENT;
|
|
}
|
|
for (i = 'A'; i <= 'Z'; ++i) {
|
|
classes[i] = CHR_LETTER | CHR_IDENT;
|
|
}
|
|
for (i = '0'; i <= '9'; ++i) {
|
|
classes[i] = CHR_DIGIT | CHR_IDENT;
|
|
}
|
|
|
|
classes[static_cast<UCHAR>('_')] = CHR_LETTER | CHR_IDENT | CHR_INTRODUCER;
|
|
classes[static_cast<UCHAR>('$')] = CHR_IDENT;
|
|
classes[static_cast<UCHAR>(' ')] = CHR_WHITE;
|
|
classes[static_cast<UCHAR>('\t')] = CHR_WHITE;
|
|
classes[static_cast<UCHAR>('\n')] = CHR_WHITE;
|
|
classes[static_cast<UCHAR>('\r')] = CHR_WHITE;
|
|
classes[static_cast<UCHAR>('\'')] = CHR_QUOTE;
|
|
classes[static_cast<UCHAR>('\"')] = CHR_DBLQUOTE;
|
|
classes[static_cast<UCHAR>('#')] = CHR_IDENT;
|
|
|
|
// zorch 0 through 7 in the fortran label vector
|
|
|
|
gpreGlob.fortran_labels[0] = 255;
|
|
|
|
// set switches and so on to default (C) values
|
|
|
|
DBB db = NULL;
|
|
|
|
gpreGlob.sw_language = lang_undef;
|
|
sw_lines = true;
|
|
gpreGlob.sw_auto = true;
|
|
gpreGlob.sw_cstring = true;
|
|
sw_alsys = false;
|
|
gpreGlob.sw_external = false;
|
|
sw_standard_out = false;
|
|
gpreGlob.sw_ansi = false;
|
|
gpreGlob.sw_version = false;
|
|
gpreGlob.sw_d_float = false;
|
|
gpreGlob.sw_sql_dialect = SQL_DIALECT_V5;
|
|
gpreGlob.dialect_specified = false;
|
|
gen_routine = C_CXX_action;
|
|
comment_start = "/*";
|
|
comment_stop = "*/";
|
|
gpreGlob.ident_pattern = "gds__%d";
|
|
gpreGlob.transaction_name = "gds__trans";
|
|
gpreGlob.database_name = "gds__database";
|
|
gpreGlob.utility_name = "gds__utility";
|
|
gpreGlob.count_name = "gds__count";
|
|
gpreGlob.slack_name = "gds__slack";
|
|
gpreGlob.global_db_count = 0;
|
|
gpreGlob.default_user = NULL;
|
|
gpreGlob.default_password = NULL;
|
|
gpreGlob.default_lc_ctype = NULL;
|
|
gpreGlob.text_subtypes = NULL;
|
|
gpreGlob.override_case = false;
|
|
|
|
gpreGlob.sw_know_interp = FALSE;
|
|
gpreGlob.sw_interp = 0;
|
|
// FSG 14.Nov.2000
|
|
sw_verbose = false;
|
|
gpreGlob.sw_sql_dialect = gpreGlob.compiletime_db_dialect = SQL_DIALECT_V5;
|
|
|
|
//
|
|
// Call a subroutine to process the input line
|
|
//
|
|
|
|
TEXT* filename_array[4] = { 0, 0, 0, 0 };
|
|
|
|
if (!get_switches(argc, argv, gpre_in_sw_table, sw_table, filename_array)) {
|
|
CPR_exit(FINI_ERROR);
|
|
}
|
|
|
|
file_name = filename_array[0];
|
|
out_file_name = filename_array[1];
|
|
|
|
const TEXT* db_filename = filename_array[2];
|
|
//TEXT* db_base_directory = filename_array[3];
|
|
|
|
if (!file_name) {
|
|
fprintf(stderr, "gpre: no source file named.\n");
|
|
CPR_exit(FINI_ERROR);
|
|
}
|
|
|
|
//
|
|
// Try to open the input file.
|
|
// If the language wasn't supplied, maybe the kind user included a language
|
|
// specific extension, and the file name fixer will find it. The file name
|
|
// fixer returns FALSE if it can't add an extension, which means there's already
|
|
// one of the right type there.
|
|
//
|
|
|
|
if (gpreGlob.sw_language == lang_undef)
|
|
for (ext_tab = dml_ext_table; gpreGlob.sw_language = ext_tab->ext_language;
|
|
ext_tab++)
|
|
{
|
|
strcpy(spare_file_name, file_name);
|
|
if (!(file_rename(spare_file_name, ext_tab->in, NULL)))
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Sigh. No such luck. Maybe there's a file lying around with a plausible
|
|
// extension and we can use that.
|
|
//
|
|
|
|
if (gpreGlob.sw_language == lang_undef)
|
|
for (ext_tab = dml_ext_table; gpreGlob.sw_language = ext_tab->ext_language;
|
|
ext_tab++)
|
|
{
|
|
strcpy(spare_file_name, file_name);
|
|
if (file_rename(spare_file_name, ext_tab->in, NULL) &&
|
|
(input_file = fopen(spare_file_name, FOPEN_READ_TYPE)))
|
|
{
|
|
file_name = spare_file_name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Well, if he won't tell me what language it is, or even give me a hint, I'm
|
|
// not going to spend all day figuring out what he wants done.
|
|
//
|
|
|
|
if (gpreGlob.sw_language == lang_undef) {
|
|
fprintf(stderr,
|
|
"gpre: can't find %s with any known extension. Giving up.\n",
|
|
file_name);
|
|
CPR_exit(FINI_ERROR);
|
|
}
|
|
|
|
//
|
|
// Having got here, we know the language, and might even have the file open.
|
|
// Better check before reopening it on ourselves. Try the file with the
|
|
// extension first (even if we have to add the extension). If we add an
|
|
// extension, and find a file with that extension, we make the file name
|
|
// point to the expanded file name string in a private buffer.
|
|
//
|
|
|
|
if (!input_file) {
|
|
strcpy(spare_file_name, file_name);
|
|
for (ext_tab = dml_ext_table;
|
|
ext_tab->ext_language != gpreGlob.sw_language;
|
|
ext_tab++)
|
|
{
|
|
; // empty loop body
|
|
}
|
|
renamed = file_rename(spare_file_name, ext_tab->in, NULL);
|
|
if (renamed &&
|
|
(input_file = fopen(spare_file_name, FOPEN_READ_TYPE)))
|
|
{
|
|
file_name = spare_file_name;
|
|
}
|
|
else if (!(input_file = fopen(file_name, FOPEN_READ_TYPE))) {
|
|
if (renamed) {
|
|
fprintf(stderr, "gpre: can't open %s or %s\n",
|
|
file_name, spare_file_name);
|
|
}
|
|
else {
|
|
fprintf(stderr, "gpre: can't open %s\n", file_name);
|
|
}
|
|
CPR_exit(FINI_ERROR);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, apply the switches and defaults we've so painfully acquired;
|
|
// adding in the language switch in case we inferred it rather than parsing it.
|
|
//
|
|
|
|
const ext_table_t* src_ext_tab = dml_ext_table;
|
|
|
|
while (src_ext_tab->ext_language != gpreGlob.sw_language) {
|
|
++src_ext_tab;
|
|
}
|
|
sw_table[0].sw_in_sw = src_ext_tab->ext_in_sw;
|
|
|
|
for (SW_TAB sw_tab = sw_table; sw_tab->sw_in_sw; sw_tab++)
|
|
{
|
|
switch (sw_tab->sw_in_sw)
|
|
{
|
|
case IN_SW_GPRE_C:
|
|
gpreGlob.sw_language = lang_c;
|
|
gpreGlob.ident_pattern = "isc_%d";
|
|
gpreGlob.utility_name = "isc_utility";
|
|
gpreGlob.count_name = "isc_count";
|
|
gpreGlob.slack_name = "isc_slack";
|
|
break;
|
|
|
|
case IN_SW_GPRE_SCXX:
|
|
case IN_SW_GPRE_CXX:
|
|
case IN_SW_GPRE_CPLUSPLUS:
|
|
gpreGlob.sw_language = lang_cxx;
|
|
gpreGlob.ident_pattern = "isc_%d";
|
|
gpreGlob.utility_name = "isc_utility";
|
|
gpreGlob.count_name = "isc_count";
|
|
gpreGlob.slack_name = "isc_slack";
|
|
gpreGlob.transaction_name = "gds_trans";
|
|
gpreGlob.database_name = "gds_database";
|
|
break;
|
|
|
|
case IN_SW_GPRE_D:
|
|
// allocate database block and link to db chain
|
|
|
|
db = (DBB) MSC_alloc_permanent(DBB_LEN);
|
|
db->dbb_next = gpreGlob.isc_databases;
|
|
|
|
// put this one in line to be next
|
|
|
|
gpreGlob.isc_databases = db;
|
|
|
|
// allocate symbol block
|
|
|
|
symbol = (gpre_sym*) MSC_alloc_permanent(SYM_LEN);
|
|
|
|
// make it a database, specifically this one
|
|
|
|
symbol->sym_type = SYM_database;
|
|
symbol->sym_object = (gpre_ctx*) db;
|
|
symbol->sym_string = gpreGlob.database_name;
|
|
|
|
// database block points to the symbol block
|
|
|
|
db->dbb_name = symbol;
|
|
|
|
// give it the file name and try to open it
|
|
|
|
db->dbb_filename = db_filename;
|
|
if (!MET_database(db, true))
|
|
CPR_exit(FINI_ERROR);
|
|
if (gpreGlob.sw_external)
|
|
db->dbb_scope = DBB_EXTERN;
|
|
#ifdef FTN_BLK_DATA
|
|
else {
|
|
gpreGlob.global_db_count = 1;
|
|
strcpy(gpreGlob.global_db_list[0].dbb_name, db->dbb_name->sym_string);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case IN_SW_GPRE_E:
|
|
gpreGlob.sw_case = true;
|
|
break;
|
|
|
|
#ifndef BOOT_BUILD
|
|
#ifdef GPRE_ADA
|
|
case IN_SW_GPRE_ADA:
|
|
#ifdef VMS
|
|
gpreGlob.ada_null_address = "system.address_zero";
|
|
#else
|
|
gpreGlob.ada_null_address = "0";
|
|
#endif
|
|
gpreGlob.sw_case = true;
|
|
gpreGlob.sw_language = lang_ada;
|
|
sw_lines = false;
|
|
gpreGlob.sw_cstring = false;
|
|
gen_routine = ADA_action;
|
|
gpreGlob.utility_name = "isc_utility";
|
|
gpreGlob.count_name = "isc_count";
|
|
gpreGlob.slack_name = "isc_slack";
|
|
gpreGlob.transaction_name = "gds_trans";
|
|
gpreGlob.database_name = "isc_database";
|
|
gpreGlob.ident_pattern = "isc_%d";
|
|
comment_start = "--";
|
|
if (db)
|
|
db->dbb_name->sym_string = "isc_database";
|
|
comment_stop = "--";
|
|
break;
|
|
|
|
case IN_SW_GPRE_ALSYS:
|
|
sw_alsys = true;
|
|
gpreGlob.sw_case = true;
|
|
gpreGlob.sw_language = lang_ada;
|
|
sw_lines = false;
|
|
gpreGlob.sw_cstring = false;
|
|
gen_routine = ADA_action;
|
|
gpreGlob.utility_name = "isc_utility";
|
|
gpreGlob.count_name = "isc_count";
|
|
gpreGlob.slack_name = "isc_slack";
|
|
gpreGlob.transaction_name = "gds_trans";
|
|
gpreGlob.database_name = "isc_database";
|
|
gpreGlob.ident_pattern = "isc_%d";
|
|
comment_start = "--";
|
|
if (db)
|
|
db->dbb_name->sym_string = "isc_database";
|
|
comment_stop = "--";
|
|
break;
|
|
#endif // GPRE_ADA
|
|
|
|
|
|
#ifdef GPRE_FORTRAN
|
|
case IN_SW_GPRE_F:
|
|
gpreGlob.sw_case = true;
|
|
gpreGlob.sw_language = lang_fortran;
|
|
sw_lines = false;
|
|
gpreGlob.sw_cstring = false;
|
|
gen_routine = FTN_action;
|
|
#ifdef sun
|
|
comment_start = "* ";
|
|
#else
|
|
comment_start = "C ";
|
|
#endif
|
|
comment_stop = " ";
|
|
|
|
// Change the patterns for v4.0
|
|
|
|
gpreGlob.ident_pattern = "isc_%d";
|
|
gpreGlob.utility_name = "isc_utility";
|
|
gpreGlob.count_name = "isc_count";
|
|
gpreGlob.slack_name = "isc_slack";
|
|
break;
|
|
#endif // GPRE_FORTRAN
|
|
|
|
#ifdef GPRE_COBOL
|
|
case IN_SW_GPRE_ANSI:
|
|
gpreGlob.sw_ansi = true;
|
|
break;
|
|
|
|
case IN_SW_GPRE_COB:
|
|
gpreGlob.sw_case = true;
|
|
gpreGlob.sw_language = lang_cobol;
|
|
comment_stop = " ";
|
|
sw_lines = false;
|
|
gpreGlob.sw_cstring = false;
|
|
gen_routine = COB_action;
|
|
break;
|
|
#endif // GPRE_COBOL
|
|
|
|
#ifdef GPRE_PASCAL
|
|
case IN_SW_GPRE_P:
|
|
gpreGlob.sw_case = true;
|
|
gpreGlob.sw_language = lang_pascal;
|
|
sw_lines = false;
|
|
gpreGlob.sw_cstring = false;
|
|
gen_routine = PAS_action;
|
|
comment_start = "(*";
|
|
comment_stop = "*)";
|
|
break;
|
|
#endif // GPRE_PASCAL
|
|
#endif // !BOOT_BUILD
|
|
|
|
case IN_SW_GPRE_D_FLOAT:
|
|
gpreGlob.sw_d_float = true;
|
|
break;
|
|
|
|
case IN_SW_GPRE_G:
|
|
gpreGlob.sw_language = lang_internal;
|
|
gen_routine = INT_CXX_action;
|
|
gpreGlob.sw_cstring = false;
|
|
gpreGlob.transaction_name = "dbb->dbb_sys_trans";
|
|
gpreGlob.sw_know_interp = TRUE;
|
|
gpreGlob.sw_interp = ttype_metadata;
|
|
break;
|
|
|
|
case IN_SW_GPRE_GXX:
|
|
/* When we get executed here the IN_SW_GPRE_G case
|
|
* has already been executed. So we just set the
|
|
* gen_routine to point to the C++ action, and be
|
|
* done with it.
|
|
*/
|
|
gen_routine = INT_CXX_action;
|
|
use_lang_internal_gxx_output = true;
|
|
break;
|
|
|
|
case IN_SW_GPRE_LANG_INTERNAL:
|
|
/* We need to reset all the variables (except gpreGlob.sw_language) to the
|
|
* default values because the IN_SW_GPRE_G case was already
|
|
* executed in the for the very first switch.
|
|
**/
|
|
gpreGlob.sw_language = lang_internal;
|
|
gen_routine = C_CXX_action;
|
|
gpreGlob.sw_cstring = true;
|
|
gpreGlob.transaction_name = "gds_trans";
|
|
gpreGlob.sw_know_interp = FALSE;
|
|
gpreGlob.sw_interp = 0;
|
|
gpreGlob.ident_pattern = "isc_%d";
|
|
gpreGlob.utility_name = "isc_utility";
|
|
gpreGlob.count_name = "isc_count";
|
|
gpreGlob.slack_name = "isc_slack";
|
|
gpreGlob.database_name = "gds_database";
|
|
break;
|
|
|
|
case IN_SW_GPRE_I:
|
|
gpreGlob.sw_ids = true;
|
|
break;
|
|
|
|
case IN_SW_GPRE_M:
|
|
gpreGlob.sw_auto = false;
|
|
break;
|
|
|
|
case IN_SW_GPRE_N:
|
|
sw_lines = false;
|
|
break;
|
|
|
|
case IN_SW_GPRE_O:
|
|
sw_standard_out = true;
|
|
gpreGlob.out_file = stdout;
|
|
break;
|
|
|
|
case IN_SW_GPRE_R:
|
|
gpreGlob.sw_raw = true;
|
|
break;
|
|
|
|
case IN_SW_GPRE_S:
|
|
gpreGlob.sw_cstring = false;
|
|
break;
|
|
|
|
case IN_SW_GPRE_T:
|
|
sw_trace = true;
|
|
break;
|
|
// FSG 14.Nov.2000
|
|
case IN_SW_GPRE_VERBOSE:
|
|
sw_verbose = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} // for (...)
|
|
|
|
if ((gpreGlob.sw_auto) && (gpreGlob.default_user || gpreGlob.default_password
|
|
|| gpreGlob.default_lc_ctype))
|
|
{
|
|
CPR_warn("gpre: -user, -password and -charset switches require -manual");
|
|
}
|
|
//
|
|
// If one of the C++ variants was used/discovered, convert to C++ for
|
|
// further internal use.
|
|
//
|
|
|
|
if (gpreGlob.sw_language == lang_cpp || gpreGlob.sw_language == lang_cplusplus)
|
|
gpreGlob.sw_language = lang_cxx;
|
|
|
|
#ifdef ALSYS_ADA
|
|
if (sw_alsys) {
|
|
for (src_ext_tab = dml_ext_table;; src_ext_tab++)
|
|
if (src_ext_tab->ext_in_sw == IN_SW_GPRE_ALSYS)
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifdef VMS
|
|
//
|
|
// If we're on VMS, we may have an RMS sequential file rather than
|
|
// a stream file, and keeping track of our place will be harder.
|
|
// So... for VMS, copy the input to a stream file.
|
|
//
|
|
// If this is Alpha OpenVMS, then we also have to do some more
|
|
// work, since RMS is a little different...
|
|
//
|
|
|
|
#ifndef __ALPHA
|
|
temp = (FILE *) gds__temp_file(TRUE, "temp", 0);
|
|
strcpy(temp_name, "temporary file");
|
|
#else
|
|
temp = (FILE *) gds__temp_file(TRUE, "temp", temp_name);
|
|
#endif
|
|
if (temp != (FILE *) - 1) {
|
|
while ((c = get_char(input_file)) != EOF)
|
|
putc(c, temp);
|
|
fclose(input_file);
|
|
#ifdef __ALPHA
|
|
fclose(temp);
|
|
temp = fopen(temp_name, FOPEN_READ_TYPE);
|
|
#endif
|
|
}
|
|
else {
|
|
fprintf(stderr, "gpre: can't open %s\n", temp_name);
|
|
CPR_exit(FINI_ERROR);
|
|
}
|
|
|
|
input_file = temp;
|
|
#endif
|
|
|
|
#if defined(GPRE_COBOL) && !defined(BOOT_BUILD)
|
|
// if cobol is defined we need both sw_cobol and sw_ansi to
|
|
// determine how the string substitution table is set up
|
|
//
|
|
|
|
if (gpreGlob.sw_language == lang_cobol)
|
|
if (gpreGlob.sw_ansi) {
|
|
if (db)
|
|
db->dbb_name->sym_string = "isc-database";
|
|
comment_start = " * ";
|
|
gpreGlob.ident_pattern = "isc-%d";
|
|
gpreGlob.transaction_name = "isc-trans";
|
|
gpreGlob.database_name = "isc-database";
|
|
gpreGlob.utility_name = "isc-utility";
|
|
gpreGlob.count_name = "isc-count";
|
|
gpreGlob.slack_name = "isc-slack";
|
|
}
|
|
else { // just to be sure :-)
|
|
comment_start = "* ";
|
|
gpreGlob.transaction_name = "ISC_TRANS";
|
|
}
|
|
|
|
COB_name_init(gpreGlob.sw_ansi);
|
|
#endif
|
|
|
|
//
|
|
// See if user has specified an interpretation on the command line,
|
|
// as might be used for SQL access.
|
|
//
|
|
|
|
if (gpreGlob.default_lc_ctype) {
|
|
if (all_digits(gpreGlob.default_lc_ctype)) {
|
|
/* Numeric name? if so assume user has hard-coded a subtype number */
|
|
|
|
gpreGlob.sw_interp = atoi(gpreGlob.default_lc_ctype);
|
|
gpreGlob.sw_know_interp = TRUE;
|
|
}
|
|
else if (compare_ASCII7z(gpreGlob.default_lc_ctype, "DYNAMIC") == 0) {
|
|
// Dynamic means use the interpretation declared at runtime
|
|
|
|
gpreGlob.sw_interp = ttype_dynamic;
|
|
gpreGlob.sw_know_interp = TRUE;
|
|
}
|
|
else if (gpreGlob.isc_databases) {
|
|
// Name resolution done by MET_load_hash_table
|
|
|
|
gpreGlob.isc_databases->dbb_c_lc_ctype = gpreGlob.default_lc_ctype;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally, open the output file, if we're not using standard out.
|
|
// If only one file name was given, make sure it has the preprocessor
|
|
// extension, then back up to that extension, zorch it, and add
|
|
// the language extension. Then you've got an output name. Take it
|
|
// and add the correct extension. If got an explicit output file
|
|
// name, use it as is unless it doesn't have an extension in which
|
|
// case use the default language extension. Finally, open the file.
|
|
// What could be easier?
|
|
//
|
|
|
|
if (!sw_standard_out) {
|
|
const ext_table_t* out_src_ext_tab = src_ext_tab;
|
|
if (use_lang_internal_gxx_output) {
|
|
out_src_ext_tab = dml_ext_table;
|
|
while (out_src_ext_tab->ext_language != lang_internal_cxx) {
|
|
++out_src_ext_tab;
|
|
}
|
|
}
|
|
|
|
renamed = explicitt = true;
|
|
if (!out_file_name) {
|
|
out_file_name = spare_out_file_name;
|
|
strcpy(spare_out_file_name, file_name);
|
|
if (renamed = file_rename(spare_out_file_name, out_src_ext_tab->in,
|
|
out_src_ext_tab->out))
|
|
{
|
|
explicitt = false;
|
|
}
|
|
}
|
|
|
|
if (renamed) {
|
|
for (p = out_file_name; *p; p++);
|
|
#ifdef VMS
|
|
while (p != out_file_name && *p != '.' && *p != ']')
|
|
#else
|
|
while (p != out_file_name && *p != '.' && *p != '/')
|
|
#endif
|
|
p--;
|
|
if (!explicitt)
|
|
*p = 0;
|
|
|
|
if (*p != '.') {
|
|
strcpy(spare_out_file_name, out_file_name);
|
|
out_file_name = spare_out_file_name;
|
|
file_rename(out_file_name, out_src_ext_tab->out, NULL);
|
|
}
|
|
}
|
|
|
|
if (!(strcmp(out_file_name, file_name))) {
|
|
fprintf(stderr,
|
|
"gpre: output file %s would duplicate input\n",
|
|
out_file_name);
|
|
CPR_exit(FINI_ERROR);
|
|
}
|
|
if ((gpreGlob.out_file = fopen(out_file_name, FOPEN_WRITE_TYPE)) == NULL) {
|
|
fprintf(stderr, "gpre: can't open output file %s\n",
|
|
out_file_name);
|
|
CPR_exit(FINI_ERROR);
|
|
}
|
|
}
|
|
|
|
// Compile modules until end of file
|
|
|
|
sw_databases = gpreGlob.isc_databases;
|
|
|
|
try {
|
|
SLONG end_position = 0;
|
|
while (end_position = compile_module(end_position,filename_array[3]));
|
|
// empty loop body
|
|
} // try
|
|
catch (const std::exception&) {} // fall through to the cleanup code
|
|
|
|
#ifdef FTN_BLK_DATA
|
|
if (gpreGlob.sw_language == lang_fortran)
|
|
FTN_fini();
|
|
#endif
|
|
|
|
MET_fini(0);
|
|
fclose(input_file);
|
|
#ifdef VMS
|
|
#ifdef __ALPHA
|
|
delete(temp_name);
|
|
#endif
|
|
#endif
|
|
|
|
if (!sw_standard_out) {
|
|
fclose(gpreGlob.out_file);
|
|
if (gpreGlob.errors_global)
|
|
unlink(out_file_name);
|
|
}
|
|
|
|
if (gpreGlob.errors_global || warnings_global) {
|
|
if (!gpreGlob.errors_global)
|
|
fprintf(stderr, "No errors, ");
|
|
else if (gpreGlob.errors_global == 1)
|
|
fprintf(stderr, "1 error, ");
|
|
else
|
|
fprintf(stderr, "%3d errors, ", gpreGlob.errors_global);
|
|
if (!warnings_global)
|
|
fprintf(stderr, "no warnings\n");
|
|
else if (warnings_global == 1)
|
|
fprintf(stderr, "1 warning\n");
|
|
else
|
|
fprintf(stderr, "%3d warnings\n", warnings_global);
|
|
}
|
|
|
|
CPR_exit((gpreGlob.errors_global) ? FINI_ERROR : FINI_OK);
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Abort this silly program.
|
|
//
|
|
|
|
void CPR_abort()
|
|
{
|
|
++fatals_global;
|
|
//throw std::exception();
|
|
throw gpre_exception("Program terminated.");
|
|
}
|
|
|
|
|
|
#ifdef DEV_BUILD
|
|
//____________________________________________________________
|
|
//
|
|
// Report an assertion failure and abort this silly program.
|
|
//
|
|
|
|
void CPR_assert(const TEXT* file, int line)
|
|
{
|
|
TEXT buffer[MAXPATHLEN << 1];
|
|
|
|
fb_utils::snprintf(buffer, sizeof(buffer),
|
|
"GPRE assertion failure file '%s' line '%d'", file, line);
|
|
CPR_bugcheck(buffer);
|
|
}
|
|
#endif
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Issue an error message.
|
|
//
|
|
|
|
void CPR_bugcheck(const TEXT* string)
|
|
{
|
|
fprintf(stderr, "*** INTERNAL BUGCHECK: %s ***\n", string);
|
|
MET_fini(0);
|
|
CPR_abort();
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Mark end of a text description.
|
|
//
|
|
|
|
void CPR_end_text(gpre_txt* text)
|
|
{
|
|
text->txt_length = (USHORT) (gpreGlob.token_global.tok_position - text->txt_position - 1);
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Issue an error message.
|
|
//
|
|
|
|
int CPR_error(const TEXT* string)
|
|
{
|
|
fprintf(stderr, "(E) %s:%d: %s\n", file_name, line_global + 1, string);
|
|
gpreGlob.errors_global++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Exit with status.
|
|
//
|
|
|
|
void CPR_exit( int stat)
|
|
{
|
|
#ifdef LINUX
|
|
|
|
if (trace_file_name[0])
|
|
{
|
|
if (trace_file)
|
|
fclose(trace_file);
|
|
unlink(trace_file_name);
|
|
}
|
|
|
|
#else
|
|
if (trace_file)
|
|
fclose(trace_file);
|
|
if (trace_file_name[0])
|
|
unlink(trace_file_name);
|
|
#endif
|
|
|
|
exit(stat);
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Issue an warning message.
|
|
//
|
|
|
|
void CPR_warn(const TEXT* string)
|
|
{
|
|
fprintf(stderr, "(W) %s:%d: %s\n", file_name, line_global + 1, string);
|
|
warnings_global++;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Fortran, being a line oriented language, sometimes needs
|
|
// to know when it is at end of line to avoid parsing into the
|
|
// next statement. CPR_eol_token normally gets the next token,
|
|
// but if the language is FORTRAN and there isn't anything else
|
|
// on the line, it fakes a dummy token to indicate end of line.
|
|
//
|
|
|
|
TOK CPR_eol_token()
|
|
{
|
|
if (gpreGlob.sw_language != lang_fortran)
|
|
return CPR_token();
|
|
|
|
// Save the information from the previous token
|
|
|
|
gpreGlob.prior_token = gpreGlob.token_global;
|
|
gpreGlob.prior_token.tok_position = last_position;
|
|
|
|
last_position =
|
|
gpreGlob.token_global.tok_position + gpreGlob.token_global.tok_length
|
|
+ gpreGlob.token_global.tok_white_space - 1;
|
|
TEXT* p = gpreGlob.token_global.tok_string;
|
|
SSHORT num_chars = 0;
|
|
|
|
// skip spaces
|
|
|
|
SSHORT c;
|
|
for (c = nextchar(); c == ' '; c = nextchar()) {
|
|
num_chars++;
|
|
*p++ = (TEXT) c;
|
|
}
|
|
|
|
// in-line comments are equivalent to end of line
|
|
|
|
if (c == '!')
|
|
while (c != '\n' && c != EOF) {
|
|
c = nextchar();
|
|
num_chars++;
|
|
}
|
|
|
|
// in-line SQL comments are equivalent to end of line
|
|
|
|
if (gpreGlob.sw_sql && (c == '-')) {
|
|
const SSHORT peek = nextchar();
|
|
if (peek != '-')
|
|
return_char(peek);
|
|
else {
|
|
while (c != '\n' && c != EOF) {
|
|
c = nextchar();
|
|
num_chars++;
|
|
}
|
|
last_position = position - 1;
|
|
}
|
|
}
|
|
|
|
if (c == EOF) {
|
|
gpreGlob.token_global.tok_symbol = NULL;
|
|
gpreGlob.token_global.tok_keyword = KW_none;
|
|
return NULL;
|
|
}
|
|
|
|
// Not EOL so back up to the begining and try again
|
|
|
|
if (c != '\n') {
|
|
return_char(c);
|
|
while (--num_chars > 0)
|
|
return_char(*--p);
|
|
return CPR_token();
|
|
}
|
|
|
|
// if we've got EOL, treat it like a semi-colon
|
|
// NOTE: the fact that the length of this token is set to 0, is used as an
|
|
// indicator elsewhere that it was a faked token
|
|
|
|
gpreGlob.token_global.tok_string[0] = ';';
|
|
gpreGlob.token_global.tok_string[1] = 0;
|
|
gpreGlob.token_global.tok_type = tok_punct;
|
|
gpreGlob.token_global.tok_length = 0;
|
|
gpreGlob.token_global.tok_white_space = 0;
|
|
gpreGlob.token_global.tok_position = position;
|
|
gpreGlob.token_global.tok_symbol = HSH_lookup(gpreGlob.token_global.tok_string);
|
|
gpreGlob.token_global.tok_keyword = (KWWORDS) gpreGlob.token_global.tok_symbol->sym_keyword;
|
|
|
|
if (sw_trace)
|
|
puts(gpreGlob.token_global.tok_string);
|
|
|
|
return &gpreGlob.token_global;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Write text from the scratch trace file into a buffer.
|
|
//
|
|
|
|
void CPR_get_text( TEXT* buffer, const gpre_txt* text)
|
|
{
|
|
SLONG start = text->txt_position;
|
|
int length = text->txt_length;
|
|
|
|
// On PC-like platforms, '\n' will be 2 bytes. The txt_position
|
|
// will be incorrect for fseek. The position is not adjusted
|
|
// just for PC-like platforms because, we use fseek () and
|
|
// getc to position ourselves at the token position.
|
|
// We should keep both character position and byte position
|
|
// and use them appropriately. for now use getc ()
|
|
//
|
|
|
|
#if (defined WIN_NT)
|
|
if (fseek(trace_file, 0L, 0))
|
|
#else
|
|
if (fseek(trace_file, start, 0))
|
|
#endif
|
|
{
|
|
fseek(trace_file, 0L, 2);
|
|
CPR_error("fseek failed for trace file");
|
|
}
|
|
#if (defined WIN_NT)
|
|
// move forward to actual position
|
|
|
|
while (start--)
|
|
getc(trace_file);
|
|
#endif
|
|
|
|
TEXT* p = buffer;
|
|
while (length--)
|
|
*p++ = getc(trace_file);
|
|
fseek(trace_file, (SLONG) 0, 2);
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// A BASIC-specific function which resides here since it reads from
|
|
// the input file. Look for a '\n' with no continuation character (&).
|
|
// Eat tokens until previous condition is satisfied.
|
|
// This function is used to "eat" a BASIC external function definition.
|
|
//
|
|
|
|
void CPR_raw_read()
|
|
{
|
|
SCHAR token_string[MAXSYMLEN];
|
|
bool continue_char = false;
|
|
|
|
SCHAR* p = token_string;
|
|
|
|
SSHORT c;
|
|
while (c = get_char(input_file))
|
|
{
|
|
position++;
|
|
if ((classes[c] == CHR_WHITE) && sw_trace && token_string) {
|
|
*p = 0;
|
|
puts(token_string);
|
|
token_string[0] = 0;
|
|
p = token_string;
|
|
}
|
|
else
|
|
*p++ = (SCHAR) c;
|
|
|
|
if (c == '\n') { // Changed assignment to comparison. Probable archaic bug
|
|
line_global++;
|
|
line_position = 0;
|
|
if (!continue_char)
|
|
return;
|
|
continue_char = false;
|
|
}
|
|
else {
|
|
line_position++;
|
|
if (classes[c] != CHR_WHITE)
|
|
continue_char = (gpreGlob.token_global.tok_keyword == KW_AMPERSAND);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Generate a syntax error.
|
|
//
|
|
|
|
void CPR_s_error(const TEXT* string)
|
|
{
|
|
TEXT s[512];
|
|
|
|
fb_utils::snprintf(s, sizeof(s),
|
|
"expected %s, encountered \"%s\"", string, gpreGlob.token_global.tok_string);
|
|
CPR_error(s);
|
|
PAR_unwind();
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Make the current position to save description text.
|
|
//
|
|
|
|
gpre_txt* CPR_start_text()
|
|
{
|
|
gpre_txt* text = (gpre_txt*) MSC_alloc(TXT_LEN);
|
|
text->txt_position = gpreGlob.token_global.tok_position - 1;
|
|
|
|
return text;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Parse and return the next token.
|
|
// If the token is a charset introducer, gobble it, grab the
|
|
// next token, and flag that token as being in a non-default
|
|
// character set.
|
|
//
|
|
|
|
TOK CPR_token()
|
|
{
|
|
TOK token = get_token();
|
|
if (!token)
|
|
return NULL;
|
|
|
|
if (token->tok_type == tok_introducer) {
|
|
gpre_sym* symbol = MSC_find_symbol(HSH_lookup(token->tok_string + 1), SYM_charset);
|
|
if (!symbol) {
|
|
TEXT err_buffer[100];
|
|
|
|
sprintf(err_buffer, "Character set not recognized: '%.50s'",
|
|
token->tok_string);
|
|
CPR_error(err_buffer);
|
|
}
|
|
token = get_token();
|
|
|
|
switch (gpreGlob.sw_sql_dialect) {
|
|
case SQL_DIALECT_V5:
|
|
if (!(isQuoted(token->tok_type)))
|
|
CPR_error("Can only tag quoted strings with character set");
|
|
else
|
|
token->tok_charset = symbol;
|
|
break;
|
|
|
|
default:
|
|
if (token->tok_type != tok_sglquoted)
|
|
CPR_error("Can only tag quoted strings with character set");
|
|
else
|
|
token->tok_charset = symbol;
|
|
break;
|
|
|
|
}
|
|
}
|
|
// use -charset switch if there is one for quoted strings
|
|
// only after a database declaration is loaded and MET_load_hash_table run.
|
|
else if (gpreGlob.default_lc_ctype && gpreGlob.text_subtypes) {
|
|
switch (gpreGlob.sw_sql_dialect) {
|
|
case SQL_DIALECT_V5:
|
|
if (isQuoted(token->tok_type)) {
|
|
token->tok_charset = MSC_find_symbol(HSH_lookup(gpreGlob.default_lc_ctype),
|
|
SYM_charset);
|
|
}
|
|
break;
|
|
default:
|
|
if (token->tok_type == tok_sglquoted) {
|
|
token->tok_charset = MSC_find_symbol(HSH_lookup(gpreGlob.default_lc_ctype),
|
|
SYM_charset);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return token;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Return true if the string consists entirely of digits.
|
|
//
|
|
|
|
static bool all_digits(const char* str1)
|
|
{
|
|
for (; *str1; str1++)
|
|
if (!(classes[static_cast<UCHAR>(*str1)] & CHR_DIGIT))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Check the command line argument which follows
|
|
// a switch which requires a string argument.
|
|
// If there is a problem, explain and return.
|
|
//
|
|
|
|
static bool arg_is_string(SLONG argc,
|
|
TEXT** argvstring,
|
|
const TEXT* errstring)
|
|
{
|
|
const TEXT* str = *++argvstring;
|
|
|
|
if (!argc || *str == '-') {
|
|
fprintf(stderr, "%s", errstring);
|
|
print_switches();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Compare two ASCII 7-bit strings, case insensitive.
|
|
// Strings are null-byte terminated.
|
|
// Return 0 if strings are equal,
|
|
// (negative) if str1 < str2
|
|
// (positive) if str1 > str2
|
|
//
|
|
|
|
static SSHORT compare_ASCII7z(const char* str1, const char* str2)
|
|
{
|
|
|
|
for (; *str1; str1++, str2++)
|
|
if (UPPER7(*str1) != UPPER7(*str2))
|
|
return (UPPER7(*str1) - UPPER7(*str2));
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Switches have been processed and files have been opened.
|
|
// Process a module and generate output.
|
|
//
|
|
|
|
static SLONG compile_module( SLONG start_position, const TEXT* base_directory)
|
|
{
|
|
// Reset miscellaneous pointers
|
|
|
|
gpreGlob.isc_databases = sw_databases;
|
|
gpreGlob.requests = NULL;
|
|
gpreGlob.events = NULL;
|
|
global_last_action = global_first_action = gpreGlob.global_functions = NULL;
|
|
|
|
// Position the input file and initialize various modules
|
|
|
|
fseek(input_file, start_position, 0);
|
|
input_char = input_buffer;
|
|
|
|
#if !(defined WIN_NT)
|
|
trace_file = (FILE *) gds__temp_file(TRUE, SCRATCH, 0);
|
|
#else
|
|
// PC-like platforms can't delete a file that is open. Therefore
|
|
// we will save the name of the temp file for later deletion.
|
|
|
|
trace_file = (FILE *) gds__temp_file(TRUE, SCRATCH, trace_file_name);
|
|
#endif
|
|
|
|
if (trace_file == (FILE *) - 1) {
|
|
trace_file = NULL;
|
|
CPR_error("Couldn't open scratch file");
|
|
return 0;
|
|
}
|
|
|
|
position = start_position;
|
|
MSC_init();
|
|
HSH_init();
|
|
PAR_init();
|
|
CMP_init();
|
|
|
|
// Take a first pass at the module
|
|
|
|
SLONG end_position = pass1(base_directory);
|
|
|
|
// finish up any based_ons that got deferred
|
|
|
|
#ifdef GPRE_FORTRAN
|
|
if (gpreGlob.sw_language == lang_fortran)
|
|
finish_based(global_first_action);
|
|
#endif
|
|
|
|
MET_fini(NULL);
|
|
PAR_fini();
|
|
|
|
if (gpreGlob.errors_global)
|
|
return end_position;
|
|
|
|
for (gpre_req* request = gpreGlob.requests; request; request = request->req_next)
|
|
{
|
|
CMP_compile_request(request);
|
|
}
|
|
|
|
fseek(input_file, start_position, 0);
|
|
input_char = input_buffer;
|
|
|
|
if (!gpreGlob.errors_global)
|
|
pass2(start_position);
|
|
|
|
return end_position;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Add the appropriate extension to a file
|
|
// name, if there's not one already. If
|
|
// the "appropriate" one is there and a
|
|
// new extension is given, use it.
|
|
//
|
|
|
|
static bool file_rename(TEXT* file_nameL,
|
|
const TEXT* extension,
|
|
const TEXT* new_extension)
|
|
{
|
|
TEXT *p;
|
|
|
|
// go to the end of the file name
|
|
|
|
for (p = file_nameL; *p; p++);
|
|
|
|
TEXT* terminator = p;
|
|
|
|
// back up to the last extension (if any)
|
|
|
|
#if defined(VMS)
|
|
while ((p != file_nameL) && (*p != '.') && (*p != ']'))
|
|
#elif defined(WIN_NT)
|
|
while ((p != file_nameL) && (*p != '.') && (*p != '/') && (*p != '\\'))
|
|
#else
|
|
while ((p != file_nameL) && (*p != '.') && (*p != '/'))
|
|
#endif
|
|
|
|
--p;
|
|
|
|
//
|
|
// There's a match and the file spec has no extension,
|
|
// so add extension.
|
|
//
|
|
|
|
if (*p != '.') {
|
|
while (*terminator++ = *extension++);
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// There's a match and an extension. If the extension in
|
|
// the table matches the one on the file, we don't want
|
|
// to add a duplicate. Otherwise add it.
|
|
//
|
|
|
|
TEXT* ext = p;
|
|
for (const TEXT* q = extension; SAME(p, q); p++, q++)
|
|
if (!*p) {
|
|
if (new_extension)
|
|
while (*ext++ = *new_extension++);
|
|
return false;
|
|
}
|
|
|
|
#ifndef VMS
|
|
// Didn't match extension, so add the extension
|
|
while (*terminator++ = *extension++);
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
#ifdef GPRE_FORTRAN
|
|
//____________________________________________________________
|
|
//
|
|
// Scan through the based_on actions
|
|
// looking for ones that were deferred
|
|
// because we didn't have a database yet.
|
|
//
|
|
// Look at each action in turn, and if it's
|
|
// a based_on with a field name rather than a
|
|
// field block pointer, complete the name parse.
|
|
// If there's a database name, find the database,
|
|
// then the relation within the database, then
|
|
// the field. Otherwise, look through all databases
|
|
// for the relation.
|
|
//
|
|
|
|
static void finish_based( act* action)
|
|
{
|
|
gpre_rel* relation;
|
|
gpre_fld* field;
|
|
TEXT s[MAXPATHLEN << 1];
|
|
|
|
for (; action; action = action->act_rest) {
|
|
if (action->act_type != ACT_basedon)
|
|
continue;
|
|
|
|
/* If there are no databases either on the command line or in
|
|
this subroutine or main program, can't do a BASED_ON. */
|
|
|
|
if (!gpreGlob.isc_databases) {
|
|
CPR_error
|
|
("No database defined. Needed for a BASED_ON operation");
|
|
continue;
|
|
}
|
|
|
|
bas* based_on = (bas*) action->act_object;
|
|
if (!based_on->bas_fld_name)
|
|
continue;
|
|
|
|
DBB db = NULL;
|
|
if (based_on->bas_db_name) {
|
|
gpre_sym* symbol = HSH_lookup(based_on->bas_db_name->str_string);
|
|
for (; symbol; symbol = symbol->sym_homonym)
|
|
if (symbol->sym_type == SYM_database)
|
|
break;
|
|
|
|
if (symbol) {
|
|
db = (DBB) symbol->sym_object;
|
|
relation =
|
|
MET_get_relation(db, based_on->bas_rel_name->str_string, "");
|
|
if (!relation) {
|
|
fb_utils::snprintf(s, sizeof(s),
|
|
"relation %s is not defined in database %s",
|
|
based_on->bas_rel_name->str_string,
|
|
based_on->bas_db_name->str_string);
|
|
CPR_error(s);
|
|
continue;
|
|
}
|
|
field = MET_field(relation, based_on->bas_fld_name->str_string);
|
|
}
|
|
else {
|
|
if (based_on->bas_flags & BAS_ambiguous) {
|
|
/* The reference could have been DB.RELATION.FIELD or
|
|
RELATION.FIELD.SEGMENT. It's not the former. Try
|
|
the latter. */
|
|
|
|
based_on->bas_fld_name = based_on->bas_rel_name;
|
|
based_on->bas_rel_name = based_on->bas_db_name;
|
|
based_on->bas_db_name = NULL;
|
|
based_on->bas_flags |= BAS_segment;
|
|
}
|
|
else {
|
|
fb_utils::snprintf(s, sizeof(s), "database %s is not defined",
|
|
based_on->bas_db_name->str_string);
|
|
CPR_error(s);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!db) {
|
|
field = NULL;
|
|
for (db = gpreGlob.isc_databases; db; db = db->dbb_next)
|
|
if (relation =
|
|
MET_get_relation(db, based_on->bas_rel_name->str_string, ""))
|
|
{
|
|
if (field) {
|
|
/* The field reference is ambiguous. It exists in more
|
|
than one database. */
|
|
|
|
fb_utils::snprintf(s, sizeof(s),
|
|
"field %s in relation %s ambiguous",
|
|
based_on->bas_fld_name->str_string,
|
|
based_on->bas_rel_name->str_string);
|
|
CPR_error(s);
|
|
break;
|
|
}
|
|
field =
|
|
MET_field(relation, based_on->bas_fld_name->str_string);
|
|
}
|
|
|
|
if (db)
|
|
continue;
|
|
if (!relation && !field) {
|
|
sprintf(s, "relation %s is not defined",
|
|
based_on->bas_rel_name->str_string);
|
|
CPR_error(s);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!field) {
|
|
sprintf(s, "field %s is not defined in relation %s",
|
|
based_on->bas_fld_name->str_string,
|
|
based_on->bas_rel_name->str_string);
|
|
CPR_error(s);
|
|
continue;
|
|
}
|
|
|
|
if ((based_on->bas_flags & BAS_segment)
|
|
&& !(field->fld_flags & FLD_blob))
|
|
{
|
|
sprintf(s, "field %s is not a blob",
|
|
field->fld_symbol->sym_string);
|
|
CPR_error(s);
|
|
continue;
|
|
}
|
|
|
|
based_on->bas_field = field;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Return a character to the input stream.
|
|
//
|
|
|
|
static int get_char( FILE * file)
|
|
{
|
|
if (input_char != input_buffer) {
|
|
return (int) *--input_char;
|
|
|
|
}
|
|
else
|
|
{
|
|
const USHORT pc = getc(file);
|
|
|
|
// Dump this char to stderr, so we can see
|
|
// what input line will cause this ugly
|
|
// core dump.
|
|
// FSG 14.Nov.2000
|
|
if (sw_verbose) {
|
|
fprintf(stderr, "%c", pc);
|
|
}
|
|
return pc;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
//
|
|
// Parse the input line arguments, saving
|
|
// interesting switches in a switch table.
|
|
// The first entry in the switch table is
|
|
// reserved for the language, and is set
|
|
// later, even if specified here.
|
|
//
|
|
|
|
static bool get_switches(int argc,
|
|
TEXT** argv,
|
|
const in_sw_tab_t* in_sw_table,
|
|
SW_TAB sw_table,
|
|
TEXT** file_array)
|
|
{
|
|
USHORT in_sw = 0; // silence uninitialized warning
|
|
|
|
//
|
|
// Read all the switches and arguments, acting only on those
|
|
// that apply immediately, since we may find out more when
|
|
// we try to open the file.
|
|
//
|
|
|
|
SW_TAB sw_table_iterator = sw_table;
|
|
|
|
for (--argc; argc; argc--)
|
|
{
|
|
TEXT* string = *++argv;
|
|
if (*string != '?')
|
|
{
|
|
if (*string != '-')
|
|
{
|
|
if (!file_array[1])
|
|
{
|
|
if (!file_array[0]) {
|
|
file_array[0] = string;
|
|
}
|
|
else {
|
|
file_array[1] = string;
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// both input and output files have been defined, hence
|
|
// there is an unknown switch
|
|
in_sw = IN_SW_GPRE_0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// iterate through the switch table, looking for matches
|
|
|
|
sw_table_iterator++;
|
|
sw_table_iterator->sw_in_sw = IN_SW_GPRE_0;
|
|
const TEXT* q;
|
|
for (const in_sw_tab_t* in_sw_table_iterator = in_sw_table;
|
|
q = in_sw_table_iterator->in_sw_name;
|
|
in_sw_table_iterator++)
|
|
{
|
|
const TEXT* p = string + 1;
|
|
|
|
// handle orphaned hyphen case
|
|
|
|
if (!*p--)
|
|
break;
|
|
|
|
// compare switch to switch name in table
|
|
|
|
while (*p) {
|
|
if (!*++p) {
|
|
sw_table_iterator->sw_in_sw = (gpre_cmd_switch)in_sw_table_iterator->in_sw;
|
|
}
|
|
if (UPPER7(*p) != *q++) {
|
|
break;
|
|
}
|
|
}
|
|
// end of input means we got a match. stop looking
|
|
|
|
if (!*p)
|
|
break;
|
|
}
|
|
in_sw = sw_table_iterator->sw_in_sw;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check here for switches that affect file look ups
|
|
* and -D so we don't lose their arguments.
|
|
* Give up here if we find a bad switch.
|
|
*/
|
|
|
|
if (*string == '?') {
|
|
in_sw = IN_SW_GPRE_0;
|
|
}
|
|
|
|
switch (in_sw) {
|
|
case IN_SW_GPRE_C:
|
|
gpreGlob.sw_language = lang_c;
|
|
sw_table_iterator--;
|
|
break;
|
|
|
|
case IN_SW_GPRE_CXX:
|
|
gpreGlob.sw_language = lang_cxx;
|
|
sw_table_iterator--;
|
|
break;
|
|
|
|
case IN_SW_GPRE_CPLUSPLUS:
|
|
gpreGlob.sw_language = lang_cplusplus;
|
|
sw_table_iterator--;
|
|
break;
|
|
|
|
case IN_SW_GPRE_GXX:
|
|
/* If we decrement sw_tab the switch is removed
|
|
* from the table and not processed in the main
|
|
* switch statement. Since IN_SW_GPRE_G will always
|
|
* be processed for lang_internal, we leave our
|
|
* switch in so we can clean up the mess left behind
|
|
* by IN_SW_GPRE_G
|
|
*/
|
|
gpreGlob.sw_language = lang_internal;
|
|
break;
|
|
|
|
case IN_SW_GPRE_G:
|
|
gpreGlob.sw_language = lang_internal;
|
|
sw_table_iterator--;
|
|
break;
|
|
|
|
#ifdef GPRE_FORTRAN
|
|
case IN_SW_GPRE_F:
|
|
gpreGlob.sw_language = lang_fortran;
|
|
sw_table_iterator--;
|
|
break;
|
|
#endif
|
|
#ifdef GPRE_PASCAL
|
|
case IN_SW_GPRE_P:
|
|
gpreGlob.sw_language = lang_pascal;
|
|
sw_table_iterator--;
|
|
break;
|
|
#endif
|
|
case IN_SW_GPRE_X:
|
|
gpreGlob.sw_external = true;
|
|
sw_table_iterator--;
|
|
break;
|
|
#ifdef GPRE_COBOL
|
|
case IN_SW_GPRE_COB:
|
|
gpreGlob.sw_language = lang_cobol;
|
|
sw_table_iterator--;
|
|
break;
|
|
#endif
|
|
case IN_SW_GPRE_LANG_INTERNAL :
|
|
gpreGlob.sw_language = lang_internal;
|
|
/*sw_tab--;*/
|
|
break;
|
|
|
|
case IN_SW_GPRE_D:
|
|
if (!arg_is_string
|
|
(--argc, argv,
|
|
"Command line syntax: -d requires database name:\n "))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
file_array[2] = *++argv;
|
|
string = *argv;
|
|
if (*string == '=')
|
|
if (!arg_is_string
|
|
(--argc, argv,
|
|
"Command line syntax: -d requires database name:\n "))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
file_array[2] = *++argv;
|
|
break;
|
|
|
|
case IN_SW_GPRE_BASE:
|
|
if (!arg_is_string
|
|
(--argc, argv,
|
|
"Command line syntax: -b requires database base directory:\n "))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
file_array[3] = *++argv;
|
|
string = *argv;
|
|
if (*string == '=')
|
|
if (!arg_is_string
|
|
(--argc, argv,
|
|
"Command line syntax: -b requires database base directory:\n "))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
file_array[3] = *++argv;
|
|
break;
|
|
|
|
case IN_SW_GPRE_HANDLES:
|
|
if (!arg_is_string(
|
|
--argc,
|
|
argv,
|
|
"Command line syntax: -h requires handle package name\n"))
|
|
{
|
|
return false;
|
|
}
|
|
strcpy(gpreGlob.ada_package, *++argv);
|
|
strcat(gpreGlob.ada_package, ".");
|
|
break;
|
|
|
|
case IN_SW_GPRE_SQLDA:
|
|
if (!arg_is_string(
|
|
--argc,
|
|
argv,
|
|
"Command line syntax: -sqlda requires NEW\n "))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (**argv != 'n' || **argv != 'N') {
|
|
fprintf(stderr,
|
|
"-sqlda : Deprecated Feature: you must use XSQLDA\n ");
|
|
print_switches();
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
case IN_SW_GPRE_SQLDIALECT:
|
|
{
|
|
int inp;
|
|
if (!arg_is_string(
|
|
--argc,
|
|
argv,
|
|
"Command line syntax: -SQL_DIALECT requires value 1, 2 or 3 \n "))
|
|
{
|
|
return false;
|
|
}
|
|
++argv;
|
|
inp = atoi(*argv);
|
|
if (inp < 1 || inp > 3) {
|
|
fprintf(stderr,
|
|
"Command line syntax: -SQL_DIALECT requires value 1, 2 or 3 \n ");
|
|
print_switches();
|
|
return false;
|
|
}
|
|
else {
|
|
gpreGlob.sw_sql_dialect = inp;
|
|
}
|
|
gpreGlob.dialect_specified = true;
|
|
break;
|
|
}
|
|
|
|
case IN_SW_GPRE_Z:
|
|
if (!gpreGlob.sw_version) {
|
|
printf("gpre version %s\n", GDS_VERSION);
|
|
}
|
|
gpreGlob.sw_version = true;
|
|
break;
|
|
|
|
case IN_SW_GPRE_0:
|
|
if (*string != '?') {
|
|
fprintf(stderr, "gpre: unknown switch %s\n", string);
|
|
}
|
|
print_switches();
|
|
return false;
|
|
|
|
case IN_SW_GPRE_USER:
|
|
if (!arg_is_string(
|
|
--argc,
|
|
argv,
|
|
"Command line syntax: -user requires user name string:\n "))
|
|
{
|
|
return false;
|
|
}
|
|
gpreGlob.default_user = *++argv;
|
|
break;
|
|
|
|
case IN_SW_GPRE_PASSWORD:
|
|
if (!arg_is_string(
|
|
--argc,
|
|
argv,
|
|
"Command line syntax: -password requires password string:\n "))
|
|
{
|
|
return false;
|
|
}
|
|
gpreGlob.default_password = *++argv;
|
|
break;
|
|
|
|
case IN_SW_GPRE_INTERP:
|
|
if (!arg_is_string(
|
|
--argc,
|
|
argv,
|
|
"Command line syntax: -charset requires character set name:\n "))
|
|
{
|
|
return false;
|
|
}
|
|
gpreGlob.default_lc_ctype = (const TEXT*) * ++argv;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
sw_table_iterator++;
|
|
sw_table_iterator->sw_in_sw = IN_SW_GPRE_0;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Parse and return the next token.
|
|
//
|
|
|
|
static TOK get_token()
|
|
{
|
|
SSHORT next;
|
|
USHORT peek;
|
|
TEXT *p, *end;
|
|
|
|
// Save the information from the previous token
|
|
|
|
gpreGlob.prior_token = gpreGlob.token_global;
|
|
gpreGlob.prior_token.tok_position = last_position;
|
|
|
|
last_position =
|
|
gpreGlob.token_global.tok_position + gpreGlob.token_global.tok_length
|
|
+ gpreGlob.token_global.tok_white_space - 1;
|
|
int start_line = line_global;
|
|
SLONG start_position = position;
|
|
gpreGlob.token_global.tok_charset = NULL;
|
|
|
|
SSHORT c = skip_white();
|
|
|
|
#ifdef GPRE_COBOL
|
|
// Skip over cobol line continuation characters
|
|
if (gpreGlob.sw_language == lang_cobol && !gpreGlob.sw_ansi)
|
|
while (line_position == 1) {
|
|
c = skip_white();
|
|
start_line = line_global;
|
|
}
|
|
#endif
|
|
|
|
// Skip fortran line continuation characters
|
|
|
|
#ifdef GPRE_FORTRAN
|
|
if (gpreGlob.sw_language == lang_fortran) {
|
|
while (line_position == 6) {
|
|
c = skip_white();
|
|
start_line = line_global;
|
|
}
|
|
if (gpreGlob.sw_sql && line_global != start_line) {
|
|
return_char(c);
|
|
gpreGlob.token_global.tok_string[0] = ';';
|
|
gpreGlob.token_global.tok_string[1] = 0;
|
|
gpreGlob.token_global.tok_type = tok_punct;
|
|
gpreGlob.token_global.tok_length = 0;
|
|
gpreGlob.token_global.tok_white_space = 0;
|
|
gpreGlob.token_global.tok_position = start_position + 1;
|
|
gpreGlob.token_global.tok_symbol = HSH_lookup(gpreGlob.token_global.tok_string);
|
|
gpreGlob.token_global.tok_keyword = (KWWORDS) gpreGlob.token_global.tok_symbol->sym_keyword;
|
|
return &gpreGlob.token_global;
|
|
}
|
|
}
|
|
#endif
|
|
// Get token rolling
|
|
|
|
p = gpreGlob.token_global.tok_string;
|
|
end = p + sizeof(gpreGlob.token_global.tok_string);
|
|
*p++ = (TEXT) c;
|
|
|
|
if (c == EOF) {
|
|
gpreGlob.token_global.tok_symbol = NULL;
|
|
gpreGlob.token_global.tok_keyword = KW_none;
|
|
return NULL;
|
|
}
|
|
|
|
gpreGlob.token_global.tok_position = position;
|
|
gpreGlob.token_global.tok_white_space = 0;
|
|
UCHAR char_class = classes[c];
|
|
|
|
#ifdef GPRE_ADA
|
|
if ((gpreGlob.sw_language == lang_ada) && (c == '\'')) {
|
|
const SSHORT c1 = nextchar();
|
|
const SSHORT c2 = nextchar();
|
|
if (c2 != '\'') {
|
|
char_class = CHR_LETTER;
|
|
}
|
|
return_char(c2);
|
|
return_char(c1);
|
|
}
|
|
#endif
|
|
|
|
bool label = false;
|
|
|
|
if (gpreGlob.sw_sql && (char_class & CHR_INTRODUCER)) {
|
|
while (classes[c = nextchar()] & CHR_IDENT) {
|
|
if (p < end) {
|
|
*p++ = (TEXT) c;
|
|
}
|
|
}
|
|
return_char(c);
|
|
gpreGlob.token_global.tok_type = tok_introducer;
|
|
}
|
|
else if (char_class & CHR_LETTER) {
|
|
while (true) {
|
|
while (classes[c = nextchar()] & CHR_IDENT)
|
|
*p++ = (TEXT) c;
|
|
if (c != '-' || gpreGlob.sw_language != lang_cobol)
|
|
break;
|
|
if (gpreGlob.sw_language == lang_cobol && gpreGlob.sw_ansi)
|
|
*p++ = (TEXT) c;
|
|
else
|
|
*p++ = '_';
|
|
}
|
|
return_char(c);
|
|
gpreGlob.token_global.tok_type = tok_ident;
|
|
}
|
|
else if (char_class & CHR_DIGIT) {
|
|
#ifdef GPRE_FORTRAN
|
|
if (gpreGlob.sw_language == lang_fortran && line_position < 7)
|
|
label = true;
|
|
#endif
|
|
while (classes[c = nextchar()] & CHR_DIGIT)
|
|
*p++ = (TEXT) c;
|
|
if (label) {
|
|
*p = 0;
|
|
remember_label(gpreGlob.token_global.tok_string);
|
|
}
|
|
if (c == '.') {
|
|
*p++ = (TEXT) c;
|
|
while (classes[c = nextchar()] & CHR_DIGIT)
|
|
*p++ = (TEXT) c;
|
|
}
|
|
if (!label && (c == 'E' || c == 'e')) {
|
|
*p++ = (TEXT) c;
|
|
c = nextchar();
|
|
if (c == '+' || c == '-')
|
|
*p++ = (TEXT) c;
|
|
else
|
|
return_char(c);
|
|
while (classes[c = nextchar()] & CHR_DIGIT)
|
|
*p++ = (TEXT) c;
|
|
}
|
|
return_char(c);
|
|
gpreGlob.token_global.tok_type = tok_number;
|
|
}
|
|
else if ((char_class & CHR_QUOTE) || (char_class & CHR_DBLQUOTE)) {
|
|
gpreGlob.token_global.tok_type = (char_class & CHR_QUOTE) ? tok_sglquoted : tok_dblquoted;
|
|
for (;;) {
|
|
next = nextchar();
|
|
if (gpreGlob.sw_language == lang_cobol && gpreGlob.sw_ansi && next == '\n') {
|
|
if (prior_line_position == 73) {
|
|
// should be a split literal
|
|
next = skip_white();
|
|
if (next != '-' || line_position != 7) {
|
|
CPR_error("unterminated quoted string");
|
|
break;
|
|
}
|
|
next = skip_white();
|
|
if (next != c) {
|
|
CPR_error("unterminated quoted string");
|
|
break;
|
|
}
|
|
next = nextchar();
|
|
gpreGlob.token_global.tok_white_space += line_position - 1;
|
|
}
|
|
else {
|
|
CPR_error("unterminated quoted string");
|
|
break;
|
|
}
|
|
}
|
|
else if (next == EOF
|
|
|| (next == '\n' && (p[-1] != '\\' || gpreGlob.sw_sql)))
|
|
{
|
|
return_char(*p);
|
|
|
|
/* Decrement, then increment line counter, for accuracy of
|
|
the error message for an unterminated quoted string. */
|
|
|
|
line_global--;
|
|
CPR_error("unterminated quoted string");
|
|
line_global++;
|
|
break;
|
|
}
|
|
|
|
/* If we can hold the literal do so, else assume it is in part
|
|
of program we do not care about */
|
|
|
|
if (next == '\\' && !gpreGlob.sw_sql &&
|
|
((gpreGlob.sw_language == lang_c) || (isLangCpp(gpreGlob.sw_language))))
|
|
{
|
|
peek = nextchar();
|
|
if (peek == '\n') {
|
|
gpreGlob.token_global.tok_white_space += 2;
|
|
}
|
|
else if (p < end) {
|
|
*p++ = (TEXT) next;
|
|
if (p < end) {
|
|
*p++ = (TEXT) peek;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
if (p < end)
|
|
*p++ = (TEXT) next;
|
|
if (next == c)
|
|
/* If 2 quotes in a row, treat 2nd as literal - bug #1530 */
|
|
{
|
|
peek = nextchar();
|
|
if (peek != c) {
|
|
return_char(peek);
|
|
break;
|
|
}
|
|
else
|
|
gpreGlob.token_global.tok_white_space++;
|
|
}
|
|
}
|
|
}
|
|
else if (c == '.') {
|
|
if (classes[c = nextchar()] & CHR_DIGIT) {
|
|
*p++ = (TEXT) c;
|
|
while (classes[c = nextchar()] & CHR_DIGIT)
|
|
*p++ = (TEXT) c;
|
|
if ((c == 'E' || c == 'e')) {
|
|
*p++ = (TEXT) c;
|
|
c = nextchar();
|
|
if (c == '+' || c == '-')
|
|
*p++ = (TEXT) c;
|
|
else
|
|
return_char(c);
|
|
while (classes[c = nextchar()] & CHR_DIGIT)
|
|
*p++ = (TEXT) c;
|
|
}
|
|
return_char(c);
|
|
gpreGlob.token_global.tok_type = tok_number;
|
|
}
|
|
else {
|
|
return_char(c);
|
|
gpreGlob.token_global.tok_type = tok_punct;
|
|
*p++ = nextchar();
|
|
*p = 0;
|
|
if (!HSH_lookup(gpreGlob.token_global.tok_string))
|
|
return_char(*--p);
|
|
}
|
|
}
|
|
else {
|
|
gpreGlob.token_global.tok_type = tok_punct;
|
|
*p++ = nextchar();
|
|
*p = 0;
|
|
if (!HSH_lookup(gpreGlob.token_global.tok_string))
|
|
return_char(*--p);
|
|
}
|
|
|
|
gpre_sym* symbol;
|
|
|
|
gpreGlob.token_global.tok_length = p - gpreGlob.token_global.tok_string;
|
|
*p++ = 0;
|
|
if (isQuoted(gpreGlob.token_global.tok_type)) {
|
|
strip_quotes(gpreGlob.token_global);
|
|
/** If the dialect is 1 then anything that is quoted is
|
|
a string. Don not lookup in the hash table to prevent
|
|
parsing confusion.
|
|
**/
|
|
if (gpreGlob.sw_sql_dialect != SQL_DIALECT_V5)
|
|
gpreGlob.token_global.tok_symbol = symbol = HSH_lookup(gpreGlob.token_global.tok_string);
|
|
else
|
|
gpreGlob.token_global.tok_symbol = symbol = NULL;
|
|
if (symbol && symbol->sym_type == SYM_keyword)
|
|
gpreGlob.token_global.tok_keyword = (KWWORDS) symbol->sym_keyword;
|
|
else
|
|
gpreGlob.token_global.tok_keyword = KW_none;
|
|
}
|
|
else if (gpreGlob.sw_case) {
|
|
if (!gpreGlob.override_case) {
|
|
gpreGlob.token_global.tok_symbol = symbol = HSH_lookup2(gpreGlob.token_global.tok_string);
|
|
if (symbol && symbol->sym_type == SYM_keyword)
|
|
gpreGlob.token_global.tok_keyword = (KWWORDS) symbol->sym_keyword;
|
|
else
|
|
gpreGlob.token_global.tok_keyword = KW_none;
|
|
}
|
|
else {
|
|
gpreGlob.token_global.tok_symbol = symbol = HSH_lookup(gpreGlob.token_global.tok_string);
|
|
if (symbol && symbol->sym_type == SYM_keyword)
|
|
gpreGlob.token_global.tok_keyword = (KWWORDS) symbol->sym_keyword;
|
|
else
|
|
gpreGlob.token_global.tok_keyword = KW_none;
|
|
gpreGlob.override_case = false;
|
|
}
|
|
}
|
|
else {
|
|
gpreGlob.token_global.tok_symbol = symbol = HSH_lookup(gpreGlob.token_global.tok_string);
|
|
if (symbol && symbol->sym_type == SYM_keyword)
|
|
gpreGlob.token_global.tok_keyword = (KWWORDS) symbol->sym_keyword;
|
|
else
|
|
gpreGlob.token_global.tok_keyword = KW_none;
|
|
}
|
|
|
|
// ** Take care of GDML context variables. Context variables are inserted
|
|
//into the hash table as it is. There is no upper casing of the variable
|
|
//name done. Hence in all likelyhood we might have missed it while looking it
|
|
//up if -e switch was specified. Hence
|
|
//IF symbol is null AND it is not a quoted string AND -e switch was specified
|
|
//THEN search again using HSH_lookup2().
|
|
//*
|
|
if ((gpreGlob.token_global.tok_symbol == NULL) && (!isQuoted(gpreGlob.token_global.tok_type))
|
|
&& gpreGlob.sw_case)
|
|
{
|
|
gpreGlob.token_global.tok_symbol = symbol = HSH_lookup2(gpreGlob.token_global.tok_string);
|
|
if (symbol && symbol->sym_type == SYM_keyword)
|
|
gpreGlob.token_global.tok_keyword = (KWWORDS) symbol->sym_keyword;
|
|
else
|
|
gpreGlob.token_global.tok_keyword = KW_none;
|
|
}
|
|
|
|
// for FORTRAN, make note of the first token in a statement
|
|
|
|
fb_assert(first_position <= MAX_USHORT);
|
|
gpreGlob.token_global.tok_first = (USHORT) first_position;
|
|
first_position = FALSE;
|
|
|
|
if (sw_trace)
|
|
puts(gpreGlob.token_global.tok_string);
|
|
|
|
return &gpreGlob.token_global;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Get the next character from the input stream.
|
|
// Also, for Fortran, mark the beginning of a statement
|
|
//
|
|
|
|
static int nextchar()
|
|
{
|
|
position++;
|
|
line_position++;
|
|
const SSHORT c = get_char(input_file);
|
|
if (c == '\n') {
|
|
line_global++;
|
|
prior_line_position = line_position;
|
|
line_position = 0;
|
|
}
|
|
|
|
// For silly fortran, mark the first token in a statement so
|
|
// we can decide to start the database field substitution string
|
|
// with a continuation indicator if appropriate.
|
|
|
|
if (line_position == 1) {
|
|
first_position = TRUE;
|
|
|
|
/* If the first character on a Fortran line is a tab, bump up the
|
|
position indicator. */
|
|
|
|
#ifdef GPRE_FORTRAN
|
|
if (gpreGlob.sw_language == lang_fortran && c == '\t')
|
|
line_position = 7;
|
|
#endif
|
|
}
|
|
|
|
// if this is a continuation line, the next token is not
|
|
// the start of a statement.
|
|
|
|
#ifdef GPRE_FORTRAN
|
|
if (gpreGlob.sw_language == lang_fortran && line_position == 6 && c != ' '
|
|
&& c != '0')
|
|
{
|
|
first_position = FALSE;
|
|
}
|
|
#endif
|
|
|
|
#ifdef GPRE_COBOL
|
|
if (gpreGlob.sw_language == lang_cobol &&
|
|
(!gpreGlob.sw_ansi && line_position == 1 && c == '-') ||
|
|
(gpreGlob.sw_ansi && line_position == 7 && c == '-'))
|
|
{
|
|
first_position = FALSE;
|
|
}
|
|
#endif
|
|
|
|
if (position > traced_position) {
|
|
traced_position = position;
|
|
fputc(c, trace_file);
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Make first pass at input file. This involves
|
|
// passing thru tokens looking for keywords. When
|
|
// a keyword is found, try to parse an action. If
|
|
// the parse is successful (an action block is returned)
|
|
// link the new action into the system data structures
|
|
// for processing on pass 2.
|
|
//
|
|
|
|
static SLONG pass1(const TEXT* base_directory)
|
|
{
|
|
// FSG 14.Nov.2000
|
|
if (sw_verbose) {
|
|
fprintf(stderr,
|
|
"*********************** PASS 1 ***************************\n");
|
|
}
|
|
|
|
while (CPR_token())
|
|
{
|
|
while (gpreGlob.token_global.tok_symbol)
|
|
{
|
|
const SLONG start = gpreGlob.token_global.tok_position;
|
|
act* action = PAR_action(base_directory);
|
|
if (action)
|
|
{
|
|
action->act_position = start;
|
|
if (!(action->act_flags & ACT_back_token)) {
|
|
action->act_length = last_position - start;
|
|
}
|
|
else {
|
|
action->act_length =
|
|
gpreGlob.prior_token.tok_position +
|
|
gpreGlob.prior_token.tok_length - 1 - start;
|
|
}
|
|
if (global_first_action) {
|
|
global_last_action->act_rest = action;
|
|
}
|
|
else {
|
|
global_first_action = action;
|
|
}
|
|
|
|
// Allow for more than one action to be generated by a token.
|
|
|
|
do
|
|
{
|
|
global_last_action = action;
|
|
if (action = action->act_rest)
|
|
{
|
|
if (action->act_type == ACT_database)
|
|
{
|
|
/* CREATE DATABASE has two actions the second one
|
|
is do generate global decl at the start of the
|
|
program file. */
|
|
|
|
global_last_action->act_rest = NULL;
|
|
action->act_rest = global_first_action;
|
|
global_first_action = action;
|
|
action->act_position = -1;
|
|
action->act_length = -1;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
action->act_position = global_last_action->act_position;
|
|
action->act_length = 0;
|
|
}
|
|
}
|
|
} while (action);
|
|
|
|
if (global_last_action->act_flags & ACT_break) {
|
|
return last_position;
|
|
}
|
|
|
|
if (!gpreGlob.token_global.tok_length &&
|
|
((int) gpreGlob.token_global.tok_keyword == (int) KW_SEMI_COLON))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (gpreGlob.isc_databases &&
|
|
(gpreGlob.isc_databases->dbb_flags & DBB_sqlca) &&
|
|
!gpreGlob.isc_databases->dbb_filename)
|
|
{
|
|
CPR_error("No database specified");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Make a second pass thru the input file turning actions into
|
|
// comments, substituting text for actions, and generating the
|
|
// output file.
|
|
//
|
|
|
|
static void pass2( SLONG start_position)
|
|
{
|
|
SLONG i;
|
|
|
|
SSHORT c = 0;
|
|
|
|
// FSG 14.Nov.2000
|
|
if (sw_verbose) {
|
|
fprintf(stderr,
|
|
"*********************** PASS 2 ***************************\n");
|
|
}
|
|
|
|
bool suppress_output = false;
|
|
|
|
const bool sw_block_comments =
|
|
gpreGlob.sw_language == lang_c ||
|
|
isLangCpp(gpreGlob.sw_language) ||
|
|
gpreGlob.sw_language == lang_pascal;
|
|
|
|
// Put out a distintive module header
|
|
|
|
if (!sw_first++)
|
|
{
|
|
for (i = 0; i < 5; ++i)
|
|
{
|
|
fprintf(gpreGlob.out_file,
|
|
"%s********** Preprocessed module -- do not edit **************%s\n",
|
|
comment_start, comment_stop);
|
|
}
|
|
fprintf(gpreGlob.out_file,
|
|
"%s**************** gpre version %s *********************%s\n",
|
|
comment_start, GDS_VERSION, comment_stop);
|
|
}
|
|
|
|
#ifdef GPRE_ADA
|
|
if ((gpreGlob.sw_language == lang_ada) &&
|
|
(gpreGlob.ada_flags & gpreGlob.ADA_create_database))
|
|
{
|
|
fprintf(gpreGlob.out_file, "with unchecked_conversion;\nwith system;\n");
|
|
}
|
|
#endif
|
|
|
|
// Let's prepare for worst case: a lot of small dirs, many "\" to duplicate.
|
|
char backlash_fixed_file_name[MAXPATHLEN + MAXPATHLEN];
|
|
{ // scope
|
|
char* p = backlash_fixed_file_name;
|
|
for (const char* q = file_name; *q;)
|
|
{
|
|
if ((*p++ = *q++) == '\\')
|
|
*p++ = '\\';
|
|
}
|
|
*p = 0;
|
|
} // scope
|
|
|
|
//
|
|
//if (sw_lines)
|
|
// fprintf (gpreGlob.out_file, "#line 1 \"%s\"\n", backlash_fixed_file_name);
|
|
//
|
|
|
|
SLONG line = 0;
|
|
bool line_pending = sw_lines;
|
|
SLONG current = 1 + start_position;
|
|
SLONG column = 0;
|
|
|
|
SSHORT comment_start_len = strlen(comment_start);
|
|
SSHORT to_skip = 0;
|
|
|
|
// Dump text until the start of the next action, then process the action.
|
|
|
|
for (const act* action = global_first_action; action; action = action->act_rest)
|
|
{
|
|
/* Dump text until the start of the next action. If a line marker
|
|
is pending and we see an end of line, dump out the marker. */
|
|
|
|
for (; current < action->act_position; current++)
|
|
{
|
|
c = get_char(input_file);
|
|
if (c == EOF) {
|
|
CPR_error("internal error -- unexpected EOF between actions");
|
|
return;
|
|
}
|
|
if (c == '\n' || !line) {
|
|
line++;
|
|
if (line_pending) {
|
|
if (line == 1)
|
|
fprintf(gpreGlob.out_file, "#line %ld \"%s\"\n", line,
|
|
backlash_fixed_file_name);
|
|
else
|
|
fprintf(gpreGlob.out_file, "\n#line %ld \"%s\"", line,
|
|
backlash_fixed_file_name);
|
|
|
|
line_pending = false;
|
|
}
|
|
if (line == 1 && c == '\n')
|
|
line++;
|
|
column = -1;
|
|
}
|
|
putc(c, gpreGlob.out_file);
|
|
if (c == '\t') {
|
|
column = (column + 8) & ~7;
|
|
}
|
|
else {
|
|
++column;
|
|
}
|
|
}
|
|
|
|
// Determine if this action is one which requires line continuation
|
|
// handling in certain languages.
|
|
|
|
const bool continue_flag =
|
|
(action->act_type == ACT_variable) ||
|
|
(action->act_type == ACT_segment) ||
|
|
(action->act_type == ACT_segment_length) ;
|
|
|
|
// Unless the action is purely a marker, insert a comment initiator
|
|
// into the output stream.
|
|
|
|
const SLONG start = column;
|
|
if (!(action->act_flags & ACT_mark)) {
|
|
if (gpreGlob.sw_language == lang_fortran) {
|
|
fputc('\n', gpreGlob.out_file);
|
|
fputs(comment_start, gpreGlob.out_file);
|
|
}
|
|
else if (gpreGlob.sw_language == lang_cobol)
|
|
if (continue_flag)
|
|
suppress_output = true;
|
|
else {
|
|
fputc('\n', gpreGlob.out_file);
|
|
fputs(comment_start, gpreGlob.out_file);
|
|
to_skip = (column < 7) ? comment_start_len - column : 0;
|
|
column = 0;
|
|
}
|
|
else
|
|
fputs(comment_start, gpreGlob.out_file);
|
|
}
|
|
|
|
// Next, dump the text of the action to the output stream.
|
|
|
|
for (i = 0; i <= action->act_length; ++i, ++current) {
|
|
if (c == EOF) {
|
|
CPR_error("internal error -- unexpected EOF in action");
|
|
return;
|
|
}
|
|
const SSHORT prior = c;
|
|
c = get_char(input_file);
|
|
if (!suppress_output) {
|
|
// close current comment to avoid nesting comments
|
|
if (sw_block_comments && !(action->act_flags & ACT_mark) &&
|
|
c == comment_start[0])
|
|
{
|
|
const SSHORT d = get_char(input_file);
|
|
return_char(d);
|
|
if (d == comment_start[1])
|
|
fputs(comment_stop, gpreGlob.out_file);
|
|
}
|
|
if (gpreGlob.sw_language != lang_cobol || !gpreGlob.sw_ansi || c == '\n'
|
|
|| to_skip-- <= 0)
|
|
{
|
|
putc(c, gpreGlob.out_file);
|
|
}
|
|
if (c == '\n') {
|
|
line++;
|
|
if ((gpreGlob.sw_language == lang_fortran) ||
|
|
(gpreGlob.sw_language == lang_ada) ||
|
|
(gpreGlob.sw_language == lang_cobol))
|
|
{
|
|
fputs(comment_start, gpreGlob.out_file);
|
|
to_skip =
|
|
(column < 7) ? comment_start_len - column : 0;
|
|
column = 0;
|
|
}
|
|
}
|
|
|
|
// reopen our comment at end of user's comment
|
|
|
|
if (sw_block_comments && !(action->act_flags & ACT_mark) &&
|
|
prior == comment_stop[0] && c == comment_stop[1])
|
|
{
|
|
fputs(comment_start, gpreGlob.out_file);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Unless action was purely a marker, insert a comment terminator.
|
|
|
|
if (!(action->act_flags & ACT_mark) && !suppress_output) {
|
|
fputs(comment_stop, gpreGlob.out_file);
|
|
if ((gpreGlob.sw_language == lang_fortran) || (gpreGlob.sw_language == lang_cobol))
|
|
fputc('\n', gpreGlob.out_file);
|
|
}
|
|
|
|
suppress_output = false;
|
|
(*gen_routine) (action, start);
|
|
if (action->act_type == ACT_routine &&
|
|
!action->act_object &&
|
|
((gpreGlob.sw_language == lang_c) || (isLangCpp(gpreGlob.sw_language))))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (action->act_flags & ACT_break)
|
|
return;
|
|
|
|
if (sw_lines)
|
|
line_pending = true;
|
|
column = 0;
|
|
to_skip = 0;
|
|
}
|
|
|
|
// We're out of actions -- dump the remaining text to the output stream.
|
|
|
|
if (!line && line_pending) {
|
|
fprintf(gpreGlob.out_file, "#line 1 \"%s\"\n", backlash_fixed_file_name);
|
|
line_pending = false;
|
|
}
|
|
|
|
|
|
while ((c = get_char(input_file)) != EOF) {
|
|
if (c == '\n' && line_pending) {
|
|
fprintf(gpreGlob.out_file, "\n#line %ld \"%s\"", line + 1, backlash_fixed_file_name);
|
|
line_pending = false;
|
|
}
|
|
if (c == EOF) {
|
|
CPR_error("internal error -- unexpected EOF in tail");
|
|
return;
|
|
}
|
|
putc(c, gpreGlob.out_file);
|
|
}
|
|
|
|
// Last but not least, generate any remaining functions
|
|
|
|
for (; gpreGlob.global_functions; gpreGlob.global_functions = gpreGlob.global_functions->act_next)
|
|
(*gen_routine) (gpreGlob.global_functions, 0);
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Print out the switch table as an
|
|
// aid to those who have forgotten or are fishing
|
|
//
|
|
|
|
static void print_switches()
|
|
{
|
|
const in_sw_tab_t* in_sw_table_iterator;
|
|
|
|
fprintf(stderr, "\tlegal switches are:\n");
|
|
for (in_sw_table_iterator = gpre_in_sw_table;
|
|
in_sw_table_iterator->in_sw;
|
|
in_sw_table_iterator++)
|
|
{
|
|
if (in_sw_table_iterator->in_sw_text) {
|
|
fprintf(stderr, "%s%s\n", in_sw_table_iterator->in_sw_name,
|
|
in_sw_table_iterator->in_sw_text);
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "\n\tand the internal 'illegal' switches are:\n");
|
|
for (in_sw_table_iterator = gpre_in_sw_table;
|
|
in_sw_table_iterator->in_sw;
|
|
in_sw_table_iterator++)
|
|
{
|
|
if (!in_sw_table_iterator->in_sw_text) {
|
|
fprintf(stderr, "%s\n", in_sw_table_iterator->in_sw_name);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Set a bit in the label vector indicating
|
|
// that a label has been used. If the label
|
|
// is bigger than the vector, punt.
|
|
//
|
|
|
|
static void remember_label(const TEXT* label_string)
|
|
{
|
|
SLONG label = atoi(label_string);
|
|
if (label < 8192) {
|
|
const UCHAR target_byte = label & 7;
|
|
label >>= 3;
|
|
gpreGlob.fortran_labels[label] |= 1 << target_byte;
|
|
}
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Return a character to the input stream.
|
|
//
|
|
|
|
static void return_char( SSHORT c)
|
|
{
|
|
|
|
--position;
|
|
--line_position;
|
|
|
|
// note putting back a new line results in incorrect line_position value
|
|
|
|
if (c == '\n') {
|
|
--line_global;
|
|
}
|
|
|
|
*input_char++ = (TEXT) c;
|
|
}
|
|
|
|
|
|
//____________________________________________________________
|
|
//
|
|
// Skip over white space and comments in input stream
|
|
//
|
|
|
|
static SSHORT skip_white()
|
|
{
|
|
SSHORT c, next;
|
|
|
|
while (true) {
|
|
if ((c = nextchar()) == EOF)
|
|
return c;
|
|
|
|
c = c & 0xff;
|
|
|
|
// skip Fortran comments
|
|
|
|
#ifdef GPRE_FORTRAN
|
|
if (gpreGlob.sw_language == lang_fortran &&
|
|
line_position == 1 && (c == 'C' || c == 'c' || c == '*'))
|
|
{
|
|
while ((c = nextchar()) != '\n' && c != EOF);
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
#ifdef GPRE_COBOL
|
|
// skip sequence numbers when ansi COBOL
|
|
|
|
if (gpreGlob.sw_language == lang_cobol && gpreGlob.sw_ansi) {
|
|
while (line_position < 7 && (c = nextchar()) != '\n' && c != EOF);
|
|
}
|
|
|
|
// skip COBOL comments and conditional compilation
|
|
|
|
if (gpreGlob.sw_language == lang_cobol &&
|
|
(!gpreGlob.sw_ansi && line_position == 1 &&
|
|
(c == 'C' || c == 'c' || c == '*' || c == '/' || c == '\\') ||
|
|
(gpreGlob.sw_ansi && line_position == 7 && c != '\t' && c != ' '
|
|
&& c != '-')))
|
|
{
|
|
while ((c = nextchar()) != '\n' && c != EOF);
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
const UCHAR char_class = classes[c];
|
|
|
|
if (char_class & CHR_WHITE) {
|
|
continue;
|
|
}
|
|
|
|
// skip in-line SQL comments
|
|
|
|
if (gpreGlob.sw_sql && (c == '-')) {
|
|
const SSHORT c2 = nextchar();
|
|
if (c2 != '-')
|
|
return_char(c2);
|
|
else {
|
|
while ((c = nextchar()) != '\n' && c != EOF);
|
|
last_position = position - 1;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* skip C, C++ and PL/I comments */
|
|
|
|
if (c == '/' &&
|
|
(gpreGlob.sw_language == lang_c ||
|
|
isLangCpp(gpreGlob.sw_language)))
|
|
{
|
|
if ((next = nextchar()) != '*') {
|
|
if (isLangCpp(gpreGlob.sw_language) && next == '/') {
|
|
while ((c = nextchar()) != '\n' && c != EOF);
|
|
continue;
|
|
}
|
|
return_char(next);
|
|
return c;
|
|
}
|
|
c = nextchar();
|
|
while ((next = nextchar()) != EOF && !(c == '*' && next == '/'))
|
|
c = next;
|
|
continue;
|
|
}
|
|
|
|
#if !defined(sun) && defined(GPRE_FORTRAN)
|
|
// skip fortran embedded comments on VMS or hpux or sgi
|
|
|
|
if (c == '!'
|
|
&& (gpreGlob.sw_language == lang_fortran))
|
|
{
|
|
/* If this character is a '!' followed by a '=', this is an
|
|
Interbase 'not equal' operator, not a Fortran comment.
|
|
Bug #307. mao 6/14/89 */
|
|
|
|
const SSHORT c3 = nextchar();
|
|
if (c3 == '=') {
|
|
return_char(c3);
|
|
return c;
|
|
}
|
|
else {
|
|
if ((c = c3) != '\n' && c != EOF)
|
|
while ((c = nextchar()) != '\n' && c != EOF);
|
|
continue;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (c == '-' && (gpreGlob.sw_sql || gpreGlob.sw_language == lang_ada)) {
|
|
if ((next = nextchar()) != '-') {
|
|
return_char(next);
|
|
return c;
|
|
}
|
|
while ((c = nextchar()) != EOF && c != '\n');
|
|
continue;
|
|
}
|
|
|
|
// skip PASCAL comments - both types
|
|
|
|
if (c == '{' && gpreGlob.sw_language == lang_pascal) {
|
|
while ((c = nextchar()) != EOF && c != '}');
|
|
continue;
|
|
}
|
|
|
|
if (c == '(' && gpreGlob.sw_language == lang_pascal) {
|
|
if ((next = nextchar()) != '*') {
|
|
return_char(next);
|
|
return c;
|
|
}
|
|
c = nextchar();
|
|
while ((next = nextchar()) != EOF && !(c == '*' && next == ')'))
|
|
c = next;
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|