ngspice/src/xspice/cmpp/pp_mod.c

222 lines
6.4 KiB
C

/*============================================================================
FILE pp_mod.c
MEMBER OF process cmpp
Copyright 1991
Georgia Tech Research Corporation
Atlanta, Georgia 30332
All Rights Reserved
PROJECT A-8503
AUTHORS
9/12/91 Steve Tynor
MODIFICATIONS
<date> <person name> <nature of modifications>
SUMMARY
This file contains the top-level driver function for preprocessing the
"cfunc.mod" file. First, the "ifspec.ifs" file is opened and parsed to
get the data that will be needed in the .mod to .c translation (See
read_ifs.c). Then the .mod file is translated. Most of the work of the
translation is handled by the UNIX 'lex' and 'yacc' utilities. This
translation is begun at the call to mod_yyparse() below. See also files:
mod_lex.l
mod_yacc.y
Note that to allow lex/yacc to be used twice (once for the ifspec.ifs
file, and then again for the cfunc.mod file), the functions created by
lex/yacc for the latter are translated using the UNIX text editor 'sed'
under the direction of the Makefile and the following 'sed scripts':
mod_lex.sed
mod_yacc.sed
Hence the call to 'mod_yyparse()' rather than 'yyparse()' below.
INTERFACES
preprocess_mod_file()
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
============================================================================*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include "mod_yacc_y.h"
extern int mod_yyparse(void);
extern void mod_yyrestart (FILE*);
extern FILE *mod_yyin;
extern FILE *mod_yyout;
extern int mod_yylineno;
extern char *mod_yytext;
extern int mod_num_errors;
extern Ifs_Table_t *mod_ifs_table;
extern char *current_filename;
extern char *prog_name;
/*---------------------------------------------------------------------------*/
/* Allocate and build a file name from the input filename by changing its
* extension (text after the last '.') in filename to ext or append .ext if
* the filename has no extension */
static char *change_extension(const char *filename, const char *ext)
{
const char * const p = strrchr(filename, '.');
const size_t prefix_len = p ? (size_t) (p - filename) : strlen(filename);
const size_t ext_len = strlen(ext);
char * const new_filename = malloc(prefix_len + ext_len + 2);
/* +1 for '.' +1 for '\0' */
if (new_filename == (char *) NULL) {
return (char *) NULL;
}
{
char *p_cur = (char *) memcpy(new_filename, filename, prefix_len) +
prefix_len;
*p_cur++ = '.';
(void) memcpy(p_cur, ext, ext_len + 1);
}
return new_filename;
} /* end of function change_extension */
/*---------------------------------------------------------------------------*/
/*
preprocess_mod_file
Function preprocess_mod_file is the top-level driver function for
preprocessing a code model file (cfunc.mod). This function calls
read_ifs_file() requesting it to read and parse the Interface
Specification file (ifspec.ifs) and place the information
contained in it into an internal data structure. It then calls
mod_yyparse() to read the cfunc.mod file and translate it
according to the Interface Specification information. Function
mod_yyparse() is automatically generated by UNIX lex/yacc
utilities.
*/
void preprocess_mod_file (
const char *filename) /* The file to read */
{
Ifs_Table_t ifs_table; /* info read from ifspec.ifs file */
int status; /* Return status */
char *output_filename = (char *) NULL; /* .mod file being written */
/*
* Read the entire ifspec.ifs file and load the data into ifs_table
*/
status = read_ifs_file (IFSPEC_FILENAME, GET_IFS_TABLE, &ifs_table);
if (status != 0) {
exit(1);
}
/* Open the cfunc.mod file defining the code model function */
if ((current_filename = gen_filename(filename, "r")) == (char *) NULL) {
print_error("ERROR - Unable to build mod file name");
exit(1);
}
if ((mod_yyin = fopen(current_filename, "r")) == (FILE *) NULL) {
print_error("ERROR - Unable to open mod file \"%s\": %s",
current_filename, strerror(errno));
exit(1);
}
{
char *output_filename_base = (char *) NULL;
if ((output_filename_base = change_extension(
filename, "c")) == (char *) NULL) {
print_error("ERROR - Could not change extension of "
"\"%s\".", filename);
exit(1);
}
if ((output_filename = gen_filename(
output_filename_base, "w")) == (char *) NULL) {
print_error("ERROR - Unable to build output file name");
exit(1);
}
free(output_filename_base);
}
if ((mod_yyout = fopen(output_filename, "w")) == (FILE *) NULL) {
/* .c file could not be opened */
print_error("ERROR - Could not open output .c file\"%s\": %s",
output_filename, strerror(errno));
exit(1);
}
mod_ifs_table = &ifs_table;
mod_num_errors = 0;
/* Define DEBUG_WITH_MOD_FILE to have the compiler use the cfunc.mod file for
* deugging instead of the cfunc.c file. */
#ifdef DEBUG_WITH_MOD_FILE
fprintf (mod_yyout, "#line 1 \"%s\"\n", current_filename);
#endif
fprintf (mod_yyout, "#include \"ngspice/cm.h\"\n");
fprintf (mod_yyout, "extern void %s(Mif_Private_t *);\n",
ifs_table.name.c_fcn_name);
#ifdef DEBUG_WITH_MOD_FILE
fprintf (mod_yyout, "#line 1 \"%s\"\n", current_filename);
#endif
mod_yylineno = 1;
if (mod_yyparse() || (mod_num_errors > 0)) {
print_error("Error parsing .mod file: \"%s\"", current_filename);
unlink(output_filename);
exit(1);
}
if (fclose(mod_yyout) != 0) {
print_error("Error closing output file \"%s\": %s",
current_filename, strerror(errno));
unlink(output_filename);
exit(1);
}
rem_ifs_table(&ifs_table);
mod_yyrestart(NULL);
free(output_filename);
free(current_filename);
} /* end of function preprocess_mod_file */
/*---------------------------------------------------------------------------*/
void
mod_yyerror (char *str)
{
fprintf (stderr, "%s: Error: \"%s\": line %d (near \'%s\'):\n\t%s.\n",
prog_name, current_filename, mod_yylineno, mod_yytext, str);
}