123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793 |
- /*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
- /* $Id$ */
- /* C O D E - G E N E R A T I N G R O U T I N E S */
- #include <stdlib.h>
- #include <string.h>
- #include "lint.h"
- #include "debug.h"
- #include "dbsymtab.h"
- #ifndef LINT
- #include <em.h>
- #else
- #include "l_em.h"
- #include "l_lint.h"
- #endif /* LINT */
- #include "botch_free.h"
- #include <alloc.h>
- #include "dataflow.h"
- #include "use_tmp.h"
- #include <flt_arith.h>
- #include "arith.h"
- #include "type.h"
- #include "idf.h"
- #include "label.h"
- #include "code.h"
- #include "stmt.h"
- #include "def.h"
- #include "expr.h"
- #include "sizes.h"
- #include "stack.h"
- #include "level.h"
- #include "decspecs.h"
- #include "declar.h"
- #include "Lpars.h"
- #include "specials.h"
- #include "atw.h"
- #include "assert.h"
- #include "LLlex.h"
- #include "align.h"
- #include "blocks.h"
- #include "code_c.h"
- #include "conversion.h"
- #include <symbol2str.h>
- #ifdef LINT
- #include "l_lint.h"
- #endif /* LINT */
- #ifdef DBSYMTAB
- #include <stb.h>
- #endif /* DBSYMTAB */
- label lab_count = 1;
- label datlab_count = 1;
- int fp_used;
- /* global function info */
- char *func_name;
- struct type *func_type;
- #ifdef LINT
- int func_notypegiven;
- #endif
- #ifdef USE_TMP
- static int tmp_id;
- static int pro_id;
- #endif /* USE_TMP */
- extern char options[];
- extern char *source;
- static void def_strings(struct string_cst *sc);
- static void prc_entry(char *name);
- static void prc_exit();
- #ifndef LINT
- void init_code(char *dst_file)
- {
- /* init_code() initialises the output file on which the
- compact EM code is written
- */
- C_init(word_size, pointer_size); /* initialise EM module */
- if (C_open(dst_file) == 0)
- fatal("cannot write to %s\n", dst_file);
- C_magic();
- C_ms_emx(word_size, pointer_size);
- #ifdef DBSYMTAB
- if (options['g']) {
- C_ms_std(source, N_SO, 0);
- stb_typedef(int_type, "int");
- stb_typedef(schar_type, "char");
- stb_typedef(long_type, "long");
- stb_typedef(short_type, "short");
- stb_typedef(uchar_type, "unsigned char");
- stb_typedef(ushort_type, "unsigned short");
- stb_typedef(ulong_type, "unsigned long");
- stb_typedef(uint_type, "unsigned int");
- stb_typedef(float_type, "float");
- stb_typedef(double_type, "double");
- stb_typedef(lngdbl_type, "long double");
- stb_typedef(void_type, "void");
- }
- #endif /* DBSYMTAB */
- #ifdef USE_TMP
- #ifdef PREPEND_SCOPES
- C_insertpart(tmp_id = C_getid());
- #endif /* PREPEND_SCOPES */
- #endif /* USE_TMP */
- }
- #endif /* LINT */
- struct string_cst *str_list = 0;
- label code_string(char *val, int len)
- {
- register struct string_cst *sc = new_string_cst();
- label dlb = data_label();
- C_ina_dlb(dlb);
- sc->next = str_list;
- str_list = sc;
- sc->sc_value = val;
- sc->sc_len = len;
- sc->sc_dlb = dlb;
- return dlb;
- }
- static void def_strings(struct string_cst *sc)
- {
- while (sc) {
- struct string_cst *sc1 = sc;
- C_df_dlb(sc->sc_dlb);
- str_cst(sc->sc_value, sc->sc_len, 1); /* string in rom */
- sc = sc->next;
- free(sc1->sc_value);
- free_string_cst(sc1);
- }
- }
- /* flush_strings() is called from program.g after each external definition */
- void flush_strings()
- {
- if (str_list) {
- def_strings(str_list);
- str_list = 0;
- }
- }
- #ifndef LINT
- void end_code()
- {
- /* end_code() performs the actions to be taken when closing
- the output stream.
- */
- if (fp_used) {
- /* floating point used */
- C_ms_flt();
- }
- C_ms_src((int)(LineNumber - 2), source);
- C_close();
- }
- #endif /* LINT */
- #ifdef PREPEND_SCOPES
- void prepend_scopes()
- {
- /* prepend_scopes() runs down the list of global idf's
- and generates those exa's, exp's, ina's and inp's
- that superior hindsight has provided.
- */
- struct stack_entry *se = local_level->sl_entry;
- #ifdef USE_TMP
- C_beginpart(tmp_id);
- #endif /* USE_TMP */
- while (se != 0) {
- struct def *df = se->se_idf->id_def;
-
- if (df && (df->df_initialized || df->df_used || df->df_alloc)) {
- code_scope(se->se_idf->id_text, df);
- }
- se = se->next;
- }
- #ifdef USE_TMP
- C_endpart(tmp_id);
- #endif /* USE_TMP */
- }
- #endif /* PREPEND_SCOPES */
- void code_scope(char *text, struct def *def)
- {
- /* generates code for one name, text, of the storage class
- as given by def, if meaningful.
- */
- int fund = def->df_type->tp_fund;
-
- switch (def->df_sc) {
- case EXTERN:
- case GLOBAL:
- if (fund == FUNCTION)
- C_exp(text);
- else
- C_exa_dnam(text);
- break;
- case STATIC:
- if (fund == FUNCTION)
- C_inp(text);
- else
- C_ina_dnam(text);
- break;
- }
- }
- static label return_label, return2_label;
- static char return_expr_occurred;
- static arith func_size;
- static int struct_return;
- static char *last_fn_given = (char *)0;
- static label file_name_label;
- /* to be called when entering a procedure */
- void begin_proc(struct decspecs *ds, struct idf *idf)
- {
- /* begin_proc() is called at the entrance of a new function
- and performs the necessary code generation:
- - a scope indicator (if needed) exp/inp
- - the procedure entry pro $name
- - reserves some space if the result of the function
- does not fit in the return area
- - a fil pseudo instruction
- */
- char *name = idf->id_text;
- struct def *def = idf->id_def;
- /* idf->id_def does not indicate the right def structure
- * when the function being defined has a parameter of the
- * same name in an old-style function definition.
- */
- while (def->df_level != L_GLOBAL) def = def->next;
- /* When we have a new-style function definition, the parameters
- * are defined first, which means that it may look as if they have
- * the greatest scope. Correct this.
- */
- if (idf->id_def == def && def->next && def->next->df_level == L_PROTO) {
- struct def *tmpdef = def->next;
- def->next = tmpdef->next;
- tmpdef->next = def;
- idf->id_def = tmpdef;
- }
- #ifndef PREPEND_SCOPES
- code_scope(name, def);
- #endif /* PREPEND_SCOPES */
- #ifdef DATAFLOW
- if (options['d'])
- DfaStartFunction(name);
- #endif /* DATAFLOW */
- /* set global function info */
- func_name = name;
- if (def->df_type->tp_fund != FUNCTION) {
- error("making function body for non-function");
- def->df_type = error_type;
- }
- func_type = def->df_type->tp_up;
- #ifdef LINT
- func_notypegiven = ds->ds_notypegiven;
- #endif
- func_size = ATW(func_type->tp_size);
- sp_occurred[SP_SETJMP] = 0;
- #ifndef USE_TMP
- C_pro_narg(name);
- #else
- C_insertpart(pro_id = C_getid());
- #endif
- if (is_struct_or_union(func_type->tp_fund)) {
- if (func_size <= 0) {
- error("unknown return type for function %s", name);
- } else {
- struct_return = 1;
- }
- }
- else
- struct_return = 0;
- /* Special arrangements if the function result doesn't fit in
- the function return area of the EM machine. The size of
- the function return area is implementation dependent.
- */
- lab_count = (label) 1;
- return_label = text_label();
- return2_label = text_label();
- return_expr_occurred = 0;
- LocalInit();
- prc_entry(name);
- if (! options['L']) { /* profiling */
- if (!last_fn_given || strcmp(last_fn_given, FileName) != 0) {
- /* previous function came from other file */
- C_df_dlb(file_name_label = data_label());
- C_con_scon(last_fn_given = FileName,
- (arith)(strlen(FileName) + 1));
- }
- /* enable debug trace of EM source */
- C_fil_dlb(file_name_label, (arith)0);
- C_lin((arith)LineNumber);
- }
- #ifdef DBSYMTAB
- if (options['g']) {
- stb_string(def, FUNCTION, name);
- if (! strcmp(name, "main")) {
- C_ms_stb_cst(name, N_MAIN, 0, (arith) 0);
- }
- }
- #endif
- }
- void end_proc(arith fbytes)
- {
- /* end_proc() deals with the code to be generated at the end of
- a function, as there is:
- - the EM ret instruction: "ret 0"
- - loading of the function result in the function
- result area if there has been a return <expr>
- in the function body (see do_return_expr())
- - indication of the use of floating points
- - indication of the number of bytes used for
- formal parameters
- - use of special identifiers such as "__setjmp"
- - "end" + number of bytes used for local variables
- */
- arith nbytes;
- char optionsn = options['n'];
- #ifdef DATAFLOW
- if (options['d'])
- DfaEndFunction();
- #endif /* DATAFLOW */
- C_df_ilb(return2_label);
- if (return_expr_occurred && struct_return == 0) {
- C_asp(-func_size);
- }
- C_df_ilb(return_label);
- prc_exit();
- if (return_expr_occurred) {
- if (struct_return != 0) {
- LoadLocal((arith) 0, pointer_size);
- C_ret(pointer_size);
- }
- else
- C_ret(func_size);
- }
- else C_ret((arith) 0);
- /* getting the number of "local" bytes is posponed until here,
- because copying the function result may need temporaries!
- However, local_level is now L_FORMAL2, because
- L_LOCAL is already unstacked. Therefore, "unstack_level" must
- also pass "sl_max_block" to the level above L_LOCAL.
- */
- nbytes = ATW(- local_level->sl_max_block);
- #ifdef USE_TMP
- C_beginpart(pro_id);
- C_pro(func_name, nbytes);
- #endif
- if (fbytes > max_int) {
- error("%s has more than %ld parameter bytes",
- func_name, (long) max_int);
- }
- C_ms_par(fbytes); /* # bytes for formals */
- if (sp_occurred[SP_SETJMP]) { /* indicate use of "__setjmp" */
- options['n'] = 1;
- C_ms_gto();
- sp_occurred[SP_SETJMP] = 0;
- }
- #ifdef USE_TMP
- C_endpart(pro_id);
- #endif
- LocalFinish();
- C_end(nbytes);
- if (nbytes > max_int) {
- error("%s has more than %ld bytes of local variables",
- func_name, (long) max_int);
- }
- options['n'] = optionsn;
- }
- void do_return()
- {
- /* do_return handles the case of a return without expression.
- This version branches to the return label, which is
- probably smarter than generating a direct return.
- Return sequences may be expensive.
- */
- #ifdef DBSYMTAB
- if (options['g']) db_line(dot.tk_file, dot.tk_line);
- #endif /* DBSYMTAB */
- C_bra(return2_label);
- }
- void do_return_expr(struct expr *expr)
- {
- /* do_return_expr() generates the expression and the jump for
- a return statement with an expression.
- */
- ch3cast(&expr, RETURN, func_type);
- code_expr(expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
- if (struct_return != 0) {
- LoadLocal((arith) 0, pointer_size);
- store_block(func_type->tp_size, func_type->tp_align);
- }
- C_bra(return_label);
- return_expr_occurred = 1;
- }
- /* struct idf *idf idf to be declared
- * struct expr *expr initialisation; NULL if absent
- * int lvl declaration level
- * int sc storage class, as in the declaration
- */
- void code_declaration(struct idf *idf, struct expr *expr, int lvl, int sc)
- {
- /* code_declaration() does the actual declaration of the
- variable indicated by "idf" on declaration level "lvl".
- If the variable is initialised, the expression is given
- in "expr", but for global and static initialisations it
- is just non-zero, as the expression is not parsed yet.
- There are some cases to be considered:
- - filter out typedefs, they don't correspond to code;
- - global variables, coded only if initialized;
- - local static variables;
- - local automatic variables;
- Since the expression may be modified in the process,
- code_declaration() frees it after use, as the caller can
- no longer do so.
-
- If there is a storage class indication (EXTERN/STATIC),
- code_declaration() will generate an exa or ina.
- The sc is the actual storage class, as given in the
- declaration.
- */
- struct def *def = idf->id_def;
- arith size = def->df_type->tp_size;
- int fund = def->df_type->tp_fund;
- int def_sc = def->df_sc;
-
- if (def_sc == TYPEDEF) { /* no code for typedefs */
- #ifdef DBSYMTAB
- if (options['g']) {
- stb_typedef(def->df_type, idf->id_text);
- }
- #endif /* DBSYMTAB */
- return;
- }
- if (lvl == L_GLOBAL) { /* global variable */
- /* is this an allocating declaration? */
- if ( (sc == 0 || sc == STATIC)
- && fund != FUNCTION
- )
- def->df_alloc = ALLOC_SEEN;
- if (expr && def_sc == STATIC && sc == EXTERN) {
- warning("%s has internal linkage", idf->id_text);
- }
- if (expr) { /* code only if initialized */
- #ifndef PREPEND_SCOPES
- code_scope(idf->id_text, def);
- #endif /* PREPEND_SCOPES */
- def->df_alloc = ALLOC_DONE;
- C_df_dnam(idf->id_text);
- }
- }
- else
- if (lvl >= L_LOCAL) { /* local variable */
- /* STATIC, EXTERN, GLOBAL, AUTO or REGISTER */
- switch (def_sc) {
- case STATIC:
- if (fund == FUNCTION) {
- /* should produce "inp $function" ??? */
- break;
- }
- /* they are handled on the spot and get an
- integer label in EM.
- */
- #ifdef DBSYMTAB
- if (options['g'] && ! expr) {
- stb_string(def, sc, idf->id_text);
- }
- #endif /* DBSYMTAB */
- C_df_dlb((label)def->df_address);
- if (expr) { /* there is an initialisation */
- }
- else { /* produce blank space */
- if (size <= 0) {
- error("size of %s unknown", idf->id_text);
- size = (arith)0;
- }
- C_bss_cst(ATW(size), (arith)0, 1);
- }
- break;
- case EXTERN:
- if (expr && !is_anon_idf(idf) && level != L_GLOBAL)
- error("cannot initialize extern %s in block"
- , idf->id_text);
- case GLOBAL:
- /* we are sure there is no expression */
- break;
- case AUTO:
- case REGISTER:
- #ifdef DBSYMTAB
- if (options['g']) {
- stb_string(def, sc, idf->id_text);
- }
- #endif /* DBSYMTAB */
- if (expr)
- loc_init(expr, idf);
- else if ((fund == ARRAY)
- && (def->df_type->tp_size == (arith)-1)) {
- error("size for local %s unknown"
- , idf->id_text);
- }
- break;
- default:
- crash("bad local storage class");
- /*NOTREACHED*/
- }
- }
- }
- void loc_init(struct expr *expr, struct idf *id)
- {
- /* loc_init() generates code for the assignment of
- expression expr to the local variable described by id.
- It frees the expression afterwards.
- */
- struct expr *e = expr;
- struct def *df = id->id_def;
- struct type *tp = df->df_type;
- static arith tmpoffset = 0;
- static arith unknownsize = 0;
-
- ASSERT(df->df_sc != STATIC);
- switch (tp->tp_fund) {
- case ARRAY:
- if (tp->tp_size == (arith) -1)
- unknownsize = 1;
- case STRUCT:
- case UNION:
- if (e != (struct expr *) 0) {
- break; /* switch */
- } else if (!tmpoffset) {/* first time for this variable */
- tmpoffset = df->df_address;
- if (unknownsize) tmpoffset = -1;
- df->df_address = data_label();
- C_df_dlb((label)df->df_address);
- } else {
- C_lae_dlb((label)df->df_address, (arith)0);
- load_block(tp->tp_size, word_align);
- if (unknownsize) {
- /* tmpoffset += tp->tp_size; */
- unknownsize = 0;
- tmpoffset = NewLocal(tp->tp_size
- , tp->tp_align
- , regtype(tp)
- , df->df_sc);
- }
- C_lal(tmpoffset);
- store_block(tp->tp_size, tmpoffset % word_align ? 1 : word_align);
- df->df_address = tmpoffset;
- tmpoffset = 0;
- }
- #ifdef DBSYMTAB
- if (options['g']) {
- stb_string(df, AUTO, id->id_text);
- }
- #endif /* DBSYMTAB */
- return;
- }
- if (ISCOMMA(e)) { /* embraced: int i = {12}; */
- while (e) {
- loc_init(e->OP_LEFT, id);
- e = e->OP_RIGHT;
- }
- }
- else { /* not embraced */
- ch3cast(&expr, '=', tp); /* may modify expr */
- #ifndef LINT
- {
- struct value vl;
- EVAL(expr, RVAL, TRUE, NO_LABEL, NO_LABEL);
- vl.vl_class = Name;
- vl.vl_data.vl_idf = id;
- vl.vl_value = (arith)0;
- store_val(&vl, tp);
- }
- #else /* LINT */
- id->id_def->df_set = 1;
- #endif /* LINT */
- free_expression(expr);
- }
- }
- void bss(struct idf *idf)
- {
- /* bss() allocates bss space for the global idf.
- */
- struct def *df = idf->id_def;
-
- #ifndef PREPEND_SCOPES
- code_scope(idf->id_text, df);
- #endif /* PREPEND_SCOPES */
- #ifdef DBSYMTAB
- if (options['g']) {
- stb_string(df, df->df_sc, idf->id_text);
- }
- #endif /* DBSYMTAB */
- if (df->df_type->tp_size <= 0) {
- if (df->df_sc != STATIC &&
- df->df_type->tp_fund == ARRAY &&
- df->df_type->tp_up &&
- df->df_type->tp_up->tp_size >= 0) {
- C_df_dnam(idf->id_text);
- C_bss_cst(ATW(df->df_type->tp_up->tp_size), (arith)0, 1);
- }
- else error("size of %s unknown (\"%s\", line %d)"
- , idf->id_text, df->df_file, df->df_line);
- } else {
- C_df_dnam(idf->id_text);
- C_bss_cst(ATW(df->df_type->tp_size), (arith)0, 1);
- }
- }
- void formal_cvt(int hasproto, struct def *df)
- {
- /* formal_cvt() converts a formal parameter of type char or
- short from int to that type. It also converts a formal
- parameter of type float from a double to a float.
- */
- struct type *tp = df->df_type;
- if (tp->tp_size != int_size &&
- (tp->tp_fund == CHAR || tp->tp_fund == SHORT)
- ) {
- LoadLocal(df->df_address, int_size);
- /* conversion(int_type, df->df_type); ???
- No, you can't do this on the stack! (CJ)
- */
- StoreLocal(df->df_address, tp->tp_size);
- } else if (tp->tp_size != double_size
- && tp->tp_fund == FLOAT
- && !hasproto) {
- LoadLocal(df->df_address, double_size);
- #ifndef LINT
- conversion(double_type, float_type);
- #endif /* LINT */
- StoreLocal(df->df_address, tp->tp_size);
- }
- }
- #ifdef LINT
- /*ARGSUSED*/
- #endif /* LINT */
- void code_expr(struct expr *expr, int val, int code, label tlbl, label flbl)
- {
- /* code_expr() is the parser's interface to the expression code
- generator. If line number trace is wanted, it generates a
- lin instruction. EVAL() is called directly.
- */
- #ifndef LINT
- if (! options['L']) /* profiling */
- C_lin((arith)(expr->ex_line));
- #ifdef DBSYMTAB
- if (options['g']) db_line(expr->ex_file, (unsigned int)expr->ex_line);
- #endif
- EVAL(expr, val, code, tlbl, flbl);
- #else /* LINT */
- lint_expr(expr, code ? USED : IGNORED);
- #endif /* LINT */
- }
- /* The FOR/WHILE/DO/SWITCH stacking mechanism:
- stack_stmt() has to be called at the entrance of a
- for, while, do or switch statement to indicate the
- EM labels where a subsequent break or continue causes
- the program to jump to.
- */
- static struct stmt_block *stmt_stack; /* top of statement stack */
- /* code_break() generates EM code needed at the occurrence of "break":
- it generates a branch instruction to the break label of the
- innermost statement in which break has a meaning.
- As "break" is legal in any of 'while', 'do', 'for' or 'switch',
- which are the only ones that are stacked, only the top of
- the stack is interesting.
- */
- void code_break()
- {
- struct stmt_block *stmt_block = stmt_stack;
- #ifdef DBSYMTAB
- if (options['g']) db_line(dot.tk_file, dot.tk_line);
- #endif /* DBSYMTAB */
- if (stmt_block)
- C_bra(stmt_block->st_break);
- else
- error("break not inside for, while, do or switch");
- }
- /* code_continue() generates EM code needed at the occurrence of
- "continue":
- it generates a branch instruction to the continue label of the
- innermost statement in which continue has a meaning.
- */
- void code_continue()
- {
- struct stmt_block *stmt_block = stmt_stack;
- while (stmt_block) {
- if (stmt_block->st_continue) {
- #ifdef DBSYMTAB
- if (options['g']) db_line(dot.tk_file, dot.tk_line);
- #endif /* DBSYMTAB */
- C_bra(stmt_block->st_continue);
- return;
- }
- stmt_block = stmt_block->next;
- }
- error("continue not inside for, while or do");
- }
- void stack_stmt(label break_label, label cont_label)
- {
- struct stmt_block *stmt_block = new_stmt_block();
- stmt_block->next = stmt_stack;
- stmt_block->st_break = break_label;
- stmt_block->st_continue = cont_label;
- stmt_stack = stmt_block;
- }
- void unstack_stmt()
- {
- /* unstack_stmt() unstacks the data of a statement
- which may contain break or continue
- */
- register struct stmt_block *sbp = stmt_stack;
- stmt_stack = sbp->next;
- free_stmt_block(sbp);
- }
- static label prc_name;
- static void prc_entry(char *name)
- {
- if (options['p']) {
- C_df_dlb(prc_name = data_label());
- C_rom_scon(name, (arith) (strlen(name) + 1));
- C_lae_dlb(prc_name, (arith) 0);
- C_cal("procentry");
- C_asp(pointer_size);
- }
- }
- static void prc_exit()
- {
- if (options['p']) {
- C_lae_dlb(prc_name, (arith) 0);
- C_cal("procexit");
- C_asp(pointer_size);
- }
- }
- #ifdef DBSYMTAB
- void db_line(char *file, unsigned int line)
- {
- static unsigned oldline;
- static char *oldfile;
- if (file != oldfile || line != oldline) {
- C_ms_std((char *) 0, N_SLINE, (int) line);
- oldline = line;
- oldfile = file;
- }
- }
- #endif /* DBSYMTAB */
|