diff --git a/.clang-format b/.clang-format index 4e2fb62b5..cf1709826 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,4 @@ ---- +--- AlignAfterOpenBracket: AlwaysBreak AllowShortFunctionsOnASingleLine: false AllowShortLoopsOnASingleLine: false diff --git a/lang/cem/cemcom.ansi/BigPars b/lang/cem/cemcom.ansi/BigPars index 882841e64..8226992a2 100644 --- a/lang/cem/cemcom.ansi/BigPars +++ b/lang/cem/cemcom.ansi/BigPars @@ -1,135 +1,135 @@ -!File: lint.h -/*#define LINT 1 *//* if defined, 'lint' is produced */ - - -!File: pathlength.h -#define PATHLENGTH 1024 /* max. length of path to file */ - - -!File: errout.h -#define ERROUT STDERR /* file pointer for writing messages */ -#define ERR_SHADOW 5 /* a syntax error overshadows error messages - until ERR_SHADOW symbols have been - accepted without syntax error */ - - -!File: idfsize.h -#define IDFSIZE 64 /* maximum significant length of an identifier */ - - -!File: numsize.h -#define NUMSIZE 256 /* maximum length of a numeric constant */ - - -!File: nparams.h -#define NPARAMS 32 /* maximum number of parameters */ -#define STDC_NPARAMS 31 /* ANSI limit on number of parameters */ - - -!File: ifdepth.h -#define IFDEPTH 256 /* maximum number of nested if-constructions */ - - -!File: density.h -#define DENSITY 3 /* see switch.[ch] for an explanation */ - - -!File: macbuf.h -#define LAPBUF 128 /* initial size of macro replacement buffer */ -#define ARGBUF 128 /* initial size of macro parameter buffer(s) */ - - -!File: strsize.h -#define ISTRSIZE 32 /* minimum number of bytes allocated for - storing a string */ -#define RSTRSIZE 16 /* step size in enlarging the memory for - the storage of a string */ - - -!File: trgt_sizes.h -#define MAXSIZE 8 /* the maximum of the SZ_* constants */ - -/* target machine sizes */ -#define SZ_CHAR 1 -#define SZ_SHORT 2 -#define SZ_WORD 4 -#define SZ_INT 4 -#define SZ_LONG 4 -#define SZ_LNGLNG -1 -#define SZ_FLOAT 4 -#define SZ_DOUBLE 8 -#define SZ_LNGDBL 8 /* for now */ -#define SZ_POINTER 4 - -/* target machine alignment requirements */ -#define AL_CHAR 1 -#define AL_SHORT SZ_SHORT -#define AL_WORD SZ_WORD -#define AL_INT SZ_WORD -#define AL_LONG SZ_WORD -#define AL_LNGLNG SZ_WORD -#define AL_FLOAT SZ_WORD -#define AL_DOUBLE SZ_WORD -#define AL_LNGDBL SZ_WORD -#define AL_POINTER SZ_WORD -#define AL_STRUCT 1 -#define AL_UNION 1 - - -!File: botch_free.h -/*#define BOTCH_FREE 1* *//* when defined, botch freed memory, as a check */ - - -!File: dataflow.h -#define DATAFLOW 1 /* produce some compile-time xref */ - - -!File: debug.h -/*#define DEBUG 1 *//* perform various self-tests */ -#define NDEBUG 1 /* disable assertions */ - - -!File: use_tmp.h -#define PREPEND_SCOPES 1 /* collect exa, exp, ina and inp commands - and if USE_TMP is defined let them - precede the rest of the generated - compact code */ -#define USE_TMP 1 /* use C_insertpart, C_endpart mechanism - to generate EM-code in the order needed - for the code-generators. If not defined, - the old-style peephole optimizer is - needed. */ - - -!File: parbufsize.h -#define PARBUFSIZE 1024 - - -!File: textsize.h -#define ITEXTSIZE 32 /* 1st piece of memory for repl. text */ - - -!File: inputtype.h -#define INP_READ_IN_ONE 1 /* read input file in one */ - - -!File: nobitfield.h -/*#define NOBITFIELD 1 *//* if NOT defined, implement bitfields */ - - -!File: static.h -#define GSTATIC /* for large global "static" arrays */ - - -!File: nocross.h -/*#define NOCROSS 1 *//* if NOT defined, cross compiler */ - - -!File: regcount.h -/*#define REGCOUNT 1 *//* count occurrences for register messages */ - - -!File: dbsymtab.h -#define DBSYMTAB 1 /* ability to produce symbol table for debugger */ - - +!File: lint.h +/*#define LINT 1 *//* if defined, 'lint' is produced */ + + +!File: pathlength.h +#define PATHLENGTH 1024 /* max. length of path to file */ + + +!File: errout.h +#define ERROUT STDERR /* file pointer for writing messages */ +#define ERR_SHADOW 5 /* a syntax error overshadows error messages + until ERR_SHADOW symbols have been + accepted without syntax error */ + + +!File: idfsize.h +#define IDFSIZE 64 /* maximum significant length of an identifier */ + + +!File: numsize.h +#define NUMSIZE 256 /* maximum length of a numeric constant */ + + +!File: nparams.h +#define NPARAMS 32 /* maximum number of parameters */ +#define STDC_NPARAMS 31 /* ANSI limit on number of parameters */ + + +!File: ifdepth.h +#define IFDEPTH 256 /* maximum number of nested if-constructions */ + + +!File: density.h +#define DENSITY 3 /* see switch.[ch] for an explanation */ + + +!File: macbuf.h +#define LAPBUF 128 /* initial size of macro replacement buffer */ +#define ARGBUF 128 /* initial size of macro parameter buffer(s) */ + + +!File: strsize.h +#define ISTRSIZE 32 /* minimum number of bytes allocated for + storing a string */ +#define RSTRSIZE 16 /* step size in enlarging the memory for + the storage of a string */ + + +!File: trgt_sizes.h +#define MAXSIZE 8 /* the maximum of the SZ_* constants */ + +/* target machine sizes */ +#define SZ_CHAR 1 +#define SZ_SHORT 2 +#define SZ_WORD 4 +#define SZ_INT 4 +#define SZ_LONG 4 +#define SZ_LNGLNG -1 +#define SZ_FLOAT 4 +#define SZ_DOUBLE 8 +#define SZ_LNGDBL 8 /* for now */ +#define SZ_POINTER 4 + +/* target machine alignment requirements */ +#define AL_CHAR 1 +#define AL_SHORT SZ_SHORT +#define AL_WORD SZ_WORD +#define AL_INT SZ_WORD +#define AL_LONG SZ_WORD +#define AL_LNGLNG SZ_WORD +#define AL_FLOAT SZ_WORD +#define AL_DOUBLE SZ_WORD +#define AL_LNGDBL SZ_WORD +#define AL_POINTER SZ_WORD +#define AL_STRUCT 1 +#define AL_UNION 1 + + +!File: botch_free.h +/*#define BOTCH_FREE 1* *//* when defined, botch freed memory, as a check */ + + +!File: dataflow.h +#define DATAFLOW 1 /* produce some compile-time xref */ + + +!File: debug.h +/*#define DEBUG 1 *//* perform various self-tests */ +#define NDEBUG 1 /* disable assertions */ + + +!File: use_tmp.h +#define PREPEND_SCOPES 1 /* collect exa, exp, ina and inp commands + and if USE_TMP is defined let them + precede the rest of the generated + compact code */ +#define USE_TMP 1 /* use C_insertpart, C_endpart mechanism + to generate EM-code in the order needed + for the code-generators. If not defined, + the old-style peephole optimizer is + needed. */ + + +!File: parbufsize.h +#define PARBUFSIZE 1024 + + +!File: textsize.h +#define ITEXTSIZE 32 /* 1st piece of memory for repl. text */ + + +!File: inputtype.h +#define INP_READ_IN_ONE 1 /* read input file in one */ + + +!File: nobitfield.h +/*#define NOBITFIELD 1 *//* if NOT defined, implement bitfields */ + + +!File: static.h +#define GSTATIC /* for large global "static" arrays */ + + +!File: nocross.h +/*#define NOCROSS 1 *//* if NOT defined, cross compiler */ + + +!File: regcount.h +/*#define REGCOUNT 1 *//* count occurrences for register messages */ + + +!File: dbsymtab.h +#define DBSYMTAB 1 /* ability to produce symbol table for debugger */ + + diff --git a/lang/cem/cemcom.ansi/declar.g b/lang/cem/cemcom.ansi/declar.g index abd7263d4..56d8596eb 100644 --- a/lang/cem/cemcom.ansi/declar.g +++ b/lang/cem/cemcom.ansi/declar.g @@ -1,772 +1,772 @@ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -/* $Id$ */ -/* DECLARATION SYNTAX PARSER */ - -{ -#include "parameters.h" -#include -#include -#include "idf.h" -#include "arith.h" -#include "LLlex.h" -#include "label.h" -#include "code.h" -#include "type.h" -#include "proto.h" -#include "struct.h" -#include "field.h" -#include "decspecs.h" -#include "declarator.h" -#include "def.h" -#include "declar.h" -#include "label.h" -#include "expr.h" -#include "sizes.h" -#include "level.h" -#include "error.h" -#include "stab.h" - -#ifdef LINT -#include "l_lint.h" -#endif /* LINT */ - -extern char options[]; -} - -/* 3.5 */ -declaration - {struct decspecs Ds;} -: - {Ds = null_decspecs;} - decl_specifiers(&Ds) - init_declarator_list(&Ds)? - ';' -; - -/* A `decl_specifiers' describes a sequence of a storage_class_specifier, - an unsigned_specifier, a size_specifier and a simple type_specifier, - which may occur in arbitrary order and each of which may be absent; - at least one of them must be present, however, since the totally - empty case has already be dealt with in `external_definition'. - This means that something like: - unsigned extern int short xx; - is perfectly legal C. - - On top of that, multiple occurrences of storage_class_specifiers, - unsigned_specifiers and size_specifiers are errors, but a second - type_specifier should end the decl_specifiers and be treated as - the name to be declared. - Such a language is not easily expressed in a grammar; enumeration - of the permutations is unattractive. We solve the problem by - having a regular grammar for the "soft" items, handling the single - occurrence of the type_specifier in the grammar (we have no choice), - collecting all data in a `struct decspecs' and turning that data - structure into what we want. - - The existence of declarations like - short typedef yepp; - makes all hope of writing a specific grammar for typedefs illusory. -*/ -/* Accept a single declaration specifier. Then accept zero or more - declaration specifiers. There can be a conflict on both - TYPE_IDENTIFIER and IDENTIFIER. - The following rule is used: - When we see a TYPE_IDENTIFIER, we accept it if no type-specifier was - given, and it is not directly followed by an identifier. If a - type-specifier was given, it is taken as the identifier being - declared. If it is followed by an identifier, we assume that an - error has been made, (e.g. unsigned typedeffed_int x;) and that - this will be detected later on. - When we see an IDENTIFIER, directly followed by another IDENTIFIER, - we assume that a typing mistake has been made, and we accept it as - an erroneous type-identifier. -*/ - -decl_specifiers /* non-empty */ (register struct decspecs *ds;) - /* Reads a non-empty decl_specifiers and fills the struct - decspecs *ds. - */ -: - single_decl_specifier(ds) - [ %while( (DOT==TYPE_IDENTIFIER - && ds->ds_size == 0 - && ds->ds_unsigned == 0 - && ds->ds_type == (struct type *)0) - || AHEAD == IDENTIFIER) /* always an error */ - single_decl_specifier(ds) - ]* - {do_decspecs(ds);} -; - -single_decl_specifier /* non_empty */ (register struct decspecs *ds;) -: - [ AUTO | STATIC | EXTERN | TYPEDEF | REGISTER ] - { if (ds->ds_sc_given) - error("repeated storage class specifier"); - ds->ds_sc_given = 1; - ds->ds_sc = DOT; - } -| - VOLATILE - { if (ds->ds_typequal & TQ_VOLATILE) - error("repeated type qualifier"); - ds->ds_typequal |= TQ_VOLATILE; - } -| - CONST - { if (ds->ds_typequal & TQ_CONST) - error("repeated type qualifier"); - ds->ds_typequal |= TQ_CONST; - } -| - [ SHORT | LONG ] - { if (ds->ds_size == LONG && DOT == LONG) - ds->ds_size = LNGLNG; - else { - if (ds->ds_size) - error("repeated size specifier"); - ds->ds_size = DOT; - } - } -| - [ SIGNED | UNSIGNED ] - { if (ds->ds_unsigned != 0) - error("repeated sign specifier"); - ds->ds_unsigned = DOT; - } -| - [ VOID | CHAR | INT | FLOAT | DOUBLE ] - { - idf2type(dot.tk_idf, &ds->ds_type); - ds->ds_typedef = 0; - } -| - %default TYPE_IDENTIFIER - { - idf2type(dot.tk_idf, &ds->ds_type); - ds->ds_typedef = 1; - } -| - %erroneous - IDENTIFIER - { - error("%s is not a type identifier", dot.tk_idf->id_text); - ds->ds_type = error_type; - if (dot.tk_idf->id_def) { - dot.tk_idf->id_def->df_type = error_type; - dot.tk_idf->id_def->df_sc = TYPEDEF; - } - } -| - %illegal - IDENTIFIER -| - struct_or_union_specifier(&ds->ds_type) -| - enum_specifier(&ds->ds_type) -; - -/* 3.5.2 */ -type_specifier(struct type **tpp;) - /* Used in struct/union declarations and in casts; only the - type is relevant. - */ - {struct decspecs Ds; Ds = null_decspecs;} -: - decl_specifiers(&Ds) - { - if (Ds.ds_sc_given) - error("storage class ignored"); - if (Ds.ds_sc == REGISTER) - error("register ignored"); - } - {*tpp = Ds.ds_type;} -; - -/* 3.5 */ -init_declarator_list(struct decspecs *ds;): - init_declarator(ds) - [ ',' init_declarator(ds) ]* -; - -init_declarator(register struct decspecs *ds;) - { - struct declarator Dc; - } -: - { - Dc = null_declarator; - } -[ - declarator(&Dc) - { - reject_params(&Dc); - declare_idf(ds, &Dc, level); -#ifdef LINT - lint_declare_idf(Dc.dc_idf, ds->ds_sc); -#endif /* LINT */ - } - [ - initializer(Dc.dc_idf, ds->ds_sc) - | - { code_declaration(Dc.dc_idf, (struct expr *) 0, level, ds->ds_sc); } - ] -] - { -#ifdef LINT - add_auto(Dc.dc_idf); -#endif /* LINT */ - remove_declarator(&Dc); - } -; - -/* 3.5.7: initializer */ -initializer(struct idf *idf; int sc;) - { - struct expr *expr = (struct expr *) 0; - int fund = idf->id_def->df_type->tp_fund; - int autoagg = (level >= L_LOCAL - && sc != STATIC - && ( fund == STRUCT - || fund == UNION - || fund == ARRAY)); - int globalflag = level == L_GLOBAL - || (level >= L_LOCAL && sc == STATIC); - } -: - { if (idf->id_def->df_type->tp_fund == FUNCTION) { - error("illegal initialization of function"); - idf->id_def->df_type->tp_fund = ERRONEOUS; - } - if (level == L_FORMAL2) - error("illegal initialization of formal parameter"); - } - '=' - { - if (AHEAD != '{' && AHEAD != STRING ) autoagg = 0; -#ifdef LINT - lint_statement(); -#endif /* LINT */ - if (globalflag) { - struct expr ex; - code_declaration(idf, &ex, level, sc); - } - else if (autoagg) - loc_init((struct expr *) 0, idf); - } - initial_value((globalflag || autoagg) ? - &(idf->id_def->df_type) - : (struct type **)0, - &expr) - { if (! globalflag) { - if (idf->id_def->df_type->tp_fund == FUNCTION) { - free_expression(expr); - expr = 0; - } -#ifdef DEBUG - print_expr("initializer-expression", expr); -#endif /* DEBUG */ -#ifdef LINT - change_state(idf, SET); -#endif /* LINT */ -#ifdef DBSYMTAB - if (options['g'] && level >= L_LOCAL && expr) { - db_line(expr->ex_file, (unsigned) expr->ex_line); - } -#endif /* DBSYMTAB */ - if (autoagg) - loc_init((struct expr *) 0, idf); - else code_declaration(idf, expr, level, sc); - } -#ifdef DBSYMTAB - if (options['g'] && globalflag) { - stb_string(idf->id_def, sc, idf->id_text); - } -#endif /* DBSYMTAB */ - idf_initialized(idf); - } -; - -/* - Functions yielding pointers to functions must be declared as, e.g., - int (*hehe(par1, par2))() char *par1, *par2; {} - Since the function heading is read as a normal declarator, - we just include the (formal) parameter list in the declarator - description list dc. -*/ -/* 3.5.4 */ -declarator(register struct declarator *dc;) - { struct formal *fm = NO_PARAMS; - struct proto *pl = NO_PROTO; - arith count; - int qual; - } -: - primary_declarator(dc) - [/*%while(1)*/ - '(' - [ %if (DOT != IDENTIFIER) - parameter_type_list(&pl) - | - formal_list(&fm) - | - /* empty */ - ] - ')' - { add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl); - fm = NO_PARAMS; - } - | - arrayer(&count) - {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);} - ]* -| - pointer(&qual) declarator(dc) - {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);} -; - -primary_declarator(register struct declarator *dc;) : - identifier(&dc->dc_idf) -| - '(' declarator(dc) ')' -; - -arrayer(arith *sizep;) - { struct expr *expr; } -: - '[' - { *sizep = (arith)-1; } - [ - constant_expression(&expr) - { - check_array_subscript(expr); - *sizep = (arith)expr->VL_VALUE; - free_expression(expr); - } - ]? - ']' -; - -formal_list (struct formal **fmp;) -: - formal(fmp) [ %persistent ',' formal(fmp) ]* -; - -formal(struct formal **fmp;) - {struct idf *idf; } -: - identifier(&idf) - { - register struct formal *new = new_formal(); - - new->fm_idf = idf; - new->next = *fmp; - *fmp = new; - if (idf->id_def && idf->id_def->df_sc == TYPEDEF) { - error("typedef name %s may not be redeclared as a parameter", idf->id_text); - } - } -; - -/* Change 2 */ -enum_specifier(register struct type **tpp;) - { - struct idf *idf; - arith l = (arith)0; - } -: - {if (*tpp) error("multiple types in declaration");} - ENUM - [ - {declare_struct(ENUM, (struct idf *) 0, tpp);} - enumerator_pack(*tpp, &l) - | - identifier(&idf) - [ - {declare_struct(ENUM, idf, tpp);} - enumerator_pack(*tpp, &l) - { -#ifdef DBSYMTAB - if (options['g']) { - stb_tag(idf->id_tag, idf->id_text); - } -#endif /*DBSYMTAB */ - } - | - {apply_struct(ENUM, idf, tpp);} - /* empty */ - ] - ] -; - -enumerator_pack(register struct type *tp; arith *lp;) : - '{' - enumerator(tp, lp) - [%while (AHEAD != '}') - ',' - enumerator(tp, lp) - ]* - [ - ',' {warning("unexpected trailing comma in enumerator pack");} - ]? - '}' - {tp->tp_size = int_size;} - /* fancy implementations that put small enums in 1 byte - or so should start here. - */ -; - -enumerator(struct type *tp; arith *lp;) - { - struct idf *idf; - struct expr *expr; - } -: - identifier(&idf) - [ - '=' - constant_expression(&expr) - { - *lp = (arith)expr->VL_VALUE; - free_expression(expr); - } - ]? - {declare_enum(tp, idf, (*lp)++);} -; - -/* 8.5 */ -struct_or_union_specifier(register struct type **tpp;) - { - int fund; - struct idf *idfX; - register struct idf *idf; - } -: - {if (*tpp) error("multiple types in declaration");} - [ STRUCT | UNION ] - {fund = DOT;} - [ - { - declare_struct(fund, (struct idf *)0, tpp); - } - struct_declaration_pack(*tpp) - | - identifier(&idfX) { idf = idfX; } - [ - { - declare_struct(fund, idf, tpp); - (idf->id_tag->tg_busy)++; - } - struct_declaration_pack(*tpp) - { - (idf->id_tag->tg_busy)--; -#ifdef DBSYMTAB - if (options['g']) { - stb_tag(idf->id_tag, idf->id_text); - } -#endif /*DBSYMTAB */ - } - | - { - /* a ';' means an empty declaration (probably) - * this means that we have to declare a new - * structure. (yegh) - */ - if (DOT == ';' && - ( !idf->id_tag || - idf->id_tag->tg_level != level || - idf->id_tag->tg_type->tp_size < 0 - )) declare_struct(fund, idf, tpp); - else apply_struct(fund, idf, tpp); - } - /* empty */ - ] - ] -; - -struct_declaration_pack(register struct type *stp;) - { - struct sdef **sdefp = &stp->tp_sdef; - arith size = (arith)0; - } -: - /* The size is only filled in after the whole struct has - been read, to prevent recursive definitions. - */ - '{' - struct_declaration(stp, &sdefp, &size)+ - '}' - {stp->tp_size = align(size, stp->tp_align); - completed(stp); - } -; - -struct_declaration(struct type *stp; struct sdef ***sdefpp; arith *szp;) - {struct type *tp;} -: - type_specifier(&tp) struct_declarator_list(tp, stp, sdefpp, szp) ';' -; - -struct_declarator_list(struct type *tp; struct type *stp; - struct sdef ***sdefpp; arith *szp;) -: - struct_declarator(tp, stp, sdefpp, szp) - [ ',' struct_declarator(tp, stp, sdefpp, szp) ]* -; - -struct_declarator(struct type *tp; struct type *stp; - struct sdef ***sdefpp; arith *szp;) - { - struct declarator Dc; - struct field *fd = 0; - } -: - { - Dc = null_declarator; - } -[ - declarator(&Dc) - {reject_params(&Dc);} - bit_expression(&fd)? -| - {Dc.dc_idf = gen_idf();} - bit_expression(&fd) -] - {add_sel(stp, declare_type(tp, &Dc), Dc.dc_idf, sdefpp, szp, fd);} - {remove_declarator(&Dc);} -; - -bit_expression(struct field **fd;) - { struct expr *expr; } -: - { - *fd = new_field(); - } - ':' - constant_expression(&expr) - { - (*fd)->fd_width = (arith)expr->VL_VALUE; - free_expression(expr); -#ifdef NOBITFIELD - error("bitfields are not implemented"); -#endif /* NOBITFIELD */ - } -; - -/* 8.7 */ -cast(struct type **tpp;) - {struct declarator Dc;} -: - {Dc = null_declarator;} - '(' - type_specifier(tpp) - abstract_declarator(&Dc) - ')' - {*tpp = declare_type(*tpp, &Dc);} - {remove_declarator(&Dc);} -; - -/* This code is an abject copy of that of 'declarator', for lack of - a two-level grammar. -*/ -abstract_declarator(register struct declarator *dc;) - { struct proto *pl = NO_PROTO; - arith count; - int qual; - } -: - primary_abstract_declarator(dc) - [ - '(' - [ - parameter_type_list(&pl) - | - /* empty */ - ] - ')' - {add_decl_unary(dc, FUNCTION, 0, (arith)0, NO_PARAMS, pl); - if (pl) remove_proto_idfs(pl); - } - | - arrayer(&count) - {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);} - ]* -| - pointer(&qual) abstract_declarator(dc) - {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);} -; - -%first first_of_parameter_type_list, parameter_type_list; - -primary_abstract_declarator(struct declarator *dc;) -: -[%if (AHEAD == ')' || first_of_parameter_type_list(AHEAD)) - /* empty */ -| - '(' abstract_declarator(dc) ')' -] -; - -parameter_type_list(struct proto **plp;) - { int save_level; } -: - { if (level > L_PROTO) { - save_level = level; - level = L_PROTO; - } else level--; - } - parameter_decl_list(plp) - [ - ',' ELLIPSIS - { register struct proto *new = new_proto(); - - new->next = *plp; - new->pl_flag = PL_ELLIPSIS; - *plp = new; - } - - ]? - { check_for_void(*plp); - if (level == L_PROTO) - level = save_level; - else level++; - } -; - -parameter_decl_list(struct proto **plp;) -: - parameter_decl(plp) - [ %while (AHEAD != ELLIPSIS) - %persistent - ',' parameter_decl(plp) - ]* -; - -parameter_decl(struct proto **plp;) - { register struct proto *new = new_proto(); - struct declarator Dc; - struct decspecs Ds; - } -: - { Dc = null_declarator; - Ds = null_decspecs; - } - decl_specifiers(&Ds) - parameter_declarator(&Dc) - { add_proto(new, &Ds, &Dc, level); - new->next = *plp; - *plp = new; - remove_declarator(&Dc); - } -; - -/* This is weird. Due to the LR structure of the ANSI C grammar - we have to duplicate the actions of 'declarator' and - 'abstract_declarator'. Calling these separately, as in - - parameter_decl: - decl_specifiers - [ - declarator - | - abstract_declarator - ] - - - gives us a conflict on the terminals '(' and '*'. E.i. on - some input, it is impossible to decide which rule we take. - Combining the two declarators into one common declarator - is out of the question, since this results in an empty - string for the non-terminal 'declarator'. - So we combine the two only for the use of parameter_decl, - since this is the only place where they don't give - conflicts. However, this makes the grammar messy. -*/ -parameter_declarator(register struct declarator *dc;) - { struct formal *fm = NO_PARAMS; - struct proto *pl = NO_PROTO; - arith count; - int qual; - } -: - primary_parameter_declarator(dc) - [ - '(' - [ %if (DOT != IDENTIFIER) - parameter_type_list(&pl) - | - formal_list(&fm) - | - /* empty */ - ] - ')' - { add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl); - reject_params(dc); - } - | - arrayer(&count) - {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);} - ]* -| - pointer(&qual) parameter_declarator(dc) - {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);} -; - -primary_parameter_declarator(register struct declarator *dc;) -: -[%if (AHEAD == ')' || first_of_parameter_type_list(AHEAD) - && (AHEAD != IDENTIFIER)) - /* empty */ -| - identifier(&dc->dc_idf) -| - '(' parameter_declarator(dc) ')' -] -; - -pointer(int *qual;) -: - '*' type_qualifier_list(qual) -; - -/* Type qualifiers may come in three flavours: - volatile, const, const volatile. - These all have different semantic properties: - - volatile: - means that the object can be modified - without prior knowledge of the implementation. - - const: - means that the object can not be modified; thus - it's illegal to use this as a l-value. - - const volatile: - means that the object can be modified without - prior knowledge of the implementation, but may - not be used as a l-value. -*/ -/* 3.5.4 */ -type_qualifier_list(int *qual;) -: - { *qual = 0; } - [ - VOLATILE - { if (*qual & TQ_VOLATILE) - error("repeated type qualifier"); - *qual |= TQ_VOLATILE; - } - | - CONST - { if (*qual & TQ_CONST) - error("repeated type qualifier"); - *qual |= TQ_CONST; - } - ]* -; - -empty: -; +/* + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ +/* $Id$ */ +/* DECLARATION SYNTAX PARSER */ + +{ +#include "parameters.h" +#include +#include +#include "idf.h" +#include "arith.h" +#include "LLlex.h" +#include "label.h" +#include "code.h" +#include "type.h" +#include "proto.h" +#include "struct.h" +#include "field.h" +#include "decspecs.h" +#include "declarator.h" +#include "def.h" +#include "declar.h" +#include "label.h" +#include "expr.h" +#include "sizes.h" +#include "level.h" +#include "error.h" +#include "stab.h" + +#ifdef LINT +#include "l_lint.h" +#endif /* LINT */ + +extern char options[]; +} + +/* 3.5 */ +declaration + {struct decspecs Ds;} +: + {Ds = null_decspecs;} + decl_specifiers(&Ds) + init_declarator_list(&Ds)? + ';' +; + +/* A `decl_specifiers' describes a sequence of a storage_class_specifier, + an unsigned_specifier, a size_specifier and a simple type_specifier, + which may occur in arbitrary order and each of which may be absent; + at least one of them must be present, however, since the totally + empty case has already be dealt with in `external_definition'. + This means that something like: + unsigned extern int short xx; + is perfectly legal C. + + On top of that, multiple occurrences of storage_class_specifiers, + unsigned_specifiers and size_specifiers are errors, but a second + type_specifier should end the decl_specifiers and be treated as + the name to be declared. + Such a language is not easily expressed in a grammar; enumeration + of the permutations is unattractive. We solve the problem by + having a regular grammar for the "soft" items, handling the single + occurrence of the type_specifier in the grammar (we have no choice), + collecting all data in a `struct decspecs' and turning that data + structure into what we want. + + The existence of declarations like + short typedef yepp; + makes all hope of writing a specific grammar for typedefs illusory. +*/ +/* Accept a single declaration specifier. Then accept zero or more + declaration specifiers. There can be a conflict on both + TYPE_IDENTIFIER and IDENTIFIER. + The following rule is used: + When we see a TYPE_IDENTIFIER, we accept it if no type-specifier was + given, and it is not directly followed by an identifier. If a + type-specifier was given, it is taken as the identifier being + declared. If it is followed by an identifier, we assume that an + error has been made, (e.g. unsigned typedeffed_int x;) and that + this will be detected later on. + When we see an IDENTIFIER, directly followed by another IDENTIFIER, + we assume that a typing mistake has been made, and we accept it as + an erroneous type-identifier. +*/ + +decl_specifiers /* non-empty */ (register struct decspecs *ds;) + /* Reads a non-empty decl_specifiers and fills the struct + decspecs *ds. + */ +: + single_decl_specifier(ds) + [ %while( (DOT==TYPE_IDENTIFIER + && ds->ds_size == 0 + && ds->ds_unsigned == 0 + && ds->ds_type == (struct type *)0) + || AHEAD == IDENTIFIER) /* always an error */ + single_decl_specifier(ds) + ]* + {do_decspecs(ds);} +; + +single_decl_specifier /* non_empty */ (register struct decspecs *ds;) +: + [ AUTO | STATIC | EXTERN | TYPEDEF | REGISTER ] + { if (ds->ds_sc_given) + error("repeated storage class specifier"); + ds->ds_sc_given = 1; + ds->ds_sc = DOT; + } +| + VOLATILE + { if (ds->ds_typequal & TQ_VOLATILE) + error("repeated type qualifier"); + ds->ds_typequal |= TQ_VOLATILE; + } +| + CONST + { if (ds->ds_typequal & TQ_CONST) + error("repeated type qualifier"); + ds->ds_typequal |= TQ_CONST; + } +| + [ SHORT | LONG ] + { if (ds->ds_size == LONG && DOT == LONG) + ds->ds_size = LNGLNG; + else { + if (ds->ds_size) + error("repeated size specifier"); + ds->ds_size = DOT; + } + } +| + [ SIGNED | UNSIGNED ] + { if (ds->ds_unsigned != 0) + error("repeated sign specifier"); + ds->ds_unsigned = DOT; + } +| + [ VOID | CHAR | INT | FLOAT | DOUBLE ] + { + idf2type(dot.tk_idf, &ds->ds_type); + ds->ds_typedef = 0; + } +| + %default TYPE_IDENTIFIER + { + idf2type(dot.tk_idf, &ds->ds_type); + ds->ds_typedef = 1; + } +| + %erroneous + IDENTIFIER + { + error("%s is not a type identifier", dot.tk_idf->id_text); + ds->ds_type = error_type; + if (dot.tk_idf->id_def) { + dot.tk_idf->id_def->df_type = error_type; + dot.tk_idf->id_def->df_sc = TYPEDEF; + } + } +| + %illegal + IDENTIFIER +| + struct_or_union_specifier(&ds->ds_type) +| + enum_specifier(&ds->ds_type) +; + +/* 3.5.2 */ +type_specifier(struct type **tpp;) + /* Used in struct/union declarations and in casts; only the + type is relevant. + */ + {struct decspecs Ds; Ds = null_decspecs;} +: + decl_specifiers(&Ds) + { + if (Ds.ds_sc_given) + error("storage class ignored"); + if (Ds.ds_sc == REGISTER) + error("register ignored"); + } + {*tpp = Ds.ds_type;} +; + +/* 3.5 */ +init_declarator_list(struct decspecs *ds;): + init_declarator(ds) + [ ',' init_declarator(ds) ]* +; + +init_declarator(register struct decspecs *ds;) + { + struct declarator Dc; + } +: + { + Dc = null_declarator; + } +[ + declarator(&Dc) + { + reject_params(&Dc); + declare_idf(ds, &Dc, level); +#ifdef LINT + lint_declare_idf(Dc.dc_idf, ds->ds_sc); +#endif /* LINT */ + } + [ + initializer(Dc.dc_idf, ds->ds_sc) + | + { code_declaration(Dc.dc_idf, (struct expr *) 0, level, ds->ds_sc); } + ] +] + { +#ifdef LINT + add_auto(Dc.dc_idf); +#endif /* LINT */ + remove_declarator(&Dc); + } +; + +/* 3.5.7: initializer */ +initializer(struct idf *idf; int sc;) + { + struct expr *expr = (struct expr *) 0; + int fund = idf->id_def->df_type->tp_fund; + int autoagg = (level >= L_LOCAL + && sc != STATIC + && ( fund == STRUCT + || fund == UNION + || fund == ARRAY)); + int globalflag = level == L_GLOBAL + || (level >= L_LOCAL && sc == STATIC); + } +: + { if (idf->id_def->df_type->tp_fund == FUNCTION) { + error("illegal initialization of function"); + idf->id_def->df_type->tp_fund = ERRONEOUS; + } + if (level == L_FORMAL2) + error("illegal initialization of formal parameter"); + } + '=' + { + if (AHEAD != '{' && AHEAD != STRING ) autoagg = 0; +#ifdef LINT + lint_statement(); +#endif /* LINT */ + if (globalflag) { + struct expr ex; + code_declaration(idf, &ex, level, sc); + } + else if (autoagg) + loc_init((struct expr *) 0, idf); + } + initial_value((globalflag || autoagg) ? + &(idf->id_def->df_type) + : (struct type **)0, + &expr) + { if (! globalflag) { + if (idf->id_def->df_type->tp_fund == FUNCTION) { + free_expression(expr); + expr = 0; + } +#ifdef DEBUG + print_expr("initializer-expression", expr); +#endif /* DEBUG */ +#ifdef LINT + change_state(idf, SET); +#endif /* LINT */ +#ifdef DBSYMTAB + if (options['g'] && level >= L_LOCAL && expr) { + db_line(expr->ex_file, (unsigned) expr->ex_line); + } +#endif /* DBSYMTAB */ + if (autoagg) + loc_init((struct expr *) 0, idf); + else code_declaration(idf, expr, level, sc); + } +#ifdef DBSYMTAB + if (options['g'] && globalflag) { + stb_string(idf->id_def, sc, idf->id_text); + } +#endif /* DBSYMTAB */ + idf_initialized(idf); + } +; + +/* + Functions yielding pointers to functions must be declared as, e.g., + int (*hehe(par1, par2))() char *par1, *par2; {} + Since the function heading is read as a normal declarator, + we just include the (formal) parameter list in the declarator + description list dc. +*/ +/* 3.5.4 */ +declarator(register struct declarator *dc;) + { struct formal *fm = NO_PARAMS; + struct proto *pl = NO_PROTO; + arith count; + int qual; + } +: + primary_declarator(dc) + [/*%while(1)*/ + '(' + [ %if (DOT != IDENTIFIER) + parameter_type_list(&pl) + | + formal_list(&fm) + | + /* empty */ + ] + ')' + { add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl); + fm = NO_PARAMS; + } + | + arrayer(&count) + {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);} + ]* +| + pointer(&qual) declarator(dc) + {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);} +; + +primary_declarator(register struct declarator *dc;) : + identifier(&dc->dc_idf) +| + '(' declarator(dc) ')' +; + +arrayer(arith *sizep;) + { struct expr *expr; } +: + '[' + { *sizep = (arith)-1; } + [ + constant_expression(&expr) + { + check_array_subscript(expr); + *sizep = (arith)expr->VL_VALUE; + free_expression(expr); + } + ]? + ']' +; + +formal_list (struct formal **fmp;) +: + formal(fmp) [ %persistent ',' formal(fmp) ]* +; + +formal(struct formal **fmp;) + {struct idf *idf; } +: + identifier(&idf) + { + register struct formal *new = new_formal(); + + new->fm_idf = idf; + new->next = *fmp; + *fmp = new; + if (idf->id_def && idf->id_def->df_sc == TYPEDEF) { + error("typedef name %s may not be redeclared as a parameter", idf->id_text); + } + } +; + +/* Change 2 */ +enum_specifier(register struct type **tpp;) + { + struct idf *idf; + arith l = (arith)0; + } +: + {if (*tpp) error("multiple types in declaration");} + ENUM + [ + {declare_struct(ENUM, (struct idf *) 0, tpp);} + enumerator_pack(*tpp, &l) + | + identifier(&idf) + [ + {declare_struct(ENUM, idf, tpp);} + enumerator_pack(*tpp, &l) + { +#ifdef DBSYMTAB + if (options['g']) { + stb_tag(idf->id_tag, idf->id_text); + } +#endif /*DBSYMTAB */ + } + | + {apply_struct(ENUM, idf, tpp);} + /* empty */ + ] + ] +; + +enumerator_pack(register struct type *tp; arith *lp;) : + '{' + enumerator(tp, lp) + [%while (AHEAD != '}') + ',' + enumerator(tp, lp) + ]* + [ + ',' {warning("unexpected trailing comma in enumerator pack");} + ]? + '}' + {tp->tp_size = int_size;} + /* fancy implementations that put small enums in 1 byte + or so should start here. + */ +; + +enumerator(struct type *tp; arith *lp;) + { + struct idf *idf; + struct expr *expr; + } +: + identifier(&idf) + [ + '=' + constant_expression(&expr) + { + *lp = (arith)expr->VL_VALUE; + free_expression(expr); + } + ]? + {declare_enum(tp, idf, (*lp)++);} +; + +/* 8.5 */ +struct_or_union_specifier(register struct type **tpp;) + { + int fund; + struct idf *idfX; + register struct idf *idf; + } +: + {if (*tpp) error("multiple types in declaration");} + [ STRUCT | UNION ] + {fund = DOT;} + [ + { + declare_struct(fund, (struct idf *)0, tpp); + } + struct_declaration_pack(*tpp) + | + identifier(&idfX) { idf = idfX; } + [ + { + declare_struct(fund, idf, tpp); + (idf->id_tag->tg_busy)++; + } + struct_declaration_pack(*tpp) + { + (idf->id_tag->tg_busy)--; +#ifdef DBSYMTAB + if (options['g']) { + stb_tag(idf->id_tag, idf->id_text); + } +#endif /*DBSYMTAB */ + } + | + { + /* a ';' means an empty declaration (probably) + * this means that we have to declare a new + * structure. (yegh) + */ + if (DOT == ';' && + ( !idf->id_tag || + idf->id_tag->tg_level != level || + idf->id_tag->tg_type->tp_size < 0 + )) declare_struct(fund, idf, tpp); + else apply_struct(fund, idf, tpp); + } + /* empty */ + ] + ] +; + +struct_declaration_pack(register struct type *stp;) + { + struct sdef **sdefp = &stp->tp_sdef; + arith size = (arith)0; + } +: + /* The size is only filled in after the whole struct has + been read, to prevent recursive definitions. + */ + '{' + struct_declaration(stp, &sdefp, &size)+ + '}' + {stp->tp_size = align(size, stp->tp_align); + completed(stp); + } +; + +struct_declaration(struct type *stp; struct sdef ***sdefpp; arith *szp;) + {struct type *tp;} +: + type_specifier(&tp) struct_declarator_list(tp, stp, sdefpp, szp) ';' +; + +struct_declarator_list(struct type *tp; struct type *stp; + struct sdef ***sdefpp; arith *szp;) +: + struct_declarator(tp, stp, sdefpp, szp) + [ ',' struct_declarator(tp, stp, sdefpp, szp) ]* +; + +struct_declarator(struct type *tp; struct type *stp; + struct sdef ***sdefpp; arith *szp;) + { + struct declarator Dc; + struct field *fd = 0; + } +: + { + Dc = null_declarator; + } +[ + declarator(&Dc) + {reject_params(&Dc);} + bit_expression(&fd)? +| + {Dc.dc_idf = gen_idf();} + bit_expression(&fd) +] + {add_sel(stp, declare_type(tp, &Dc), Dc.dc_idf, sdefpp, szp, fd);} + {remove_declarator(&Dc);} +; + +bit_expression(struct field **fd;) + { struct expr *expr; } +: + { + *fd = new_field(); + } + ':' + constant_expression(&expr) + { + (*fd)->fd_width = (arith)expr->VL_VALUE; + free_expression(expr); +#ifdef NOBITFIELD + error("bitfields are not implemented"); +#endif /* NOBITFIELD */ + } +; + +/* 8.7 */ +cast(struct type **tpp;) + {struct declarator Dc;} +: + {Dc = null_declarator;} + '(' + type_specifier(tpp) + abstract_declarator(&Dc) + ')' + {*tpp = declare_type(*tpp, &Dc);} + {remove_declarator(&Dc);} +; + +/* This code is an abject copy of that of 'declarator', for lack of + a two-level grammar. +*/ +abstract_declarator(register struct declarator *dc;) + { struct proto *pl = NO_PROTO; + arith count; + int qual; + } +: + primary_abstract_declarator(dc) + [ + '(' + [ + parameter_type_list(&pl) + | + /* empty */ + ] + ')' + {add_decl_unary(dc, FUNCTION, 0, (arith)0, NO_PARAMS, pl); + if (pl) remove_proto_idfs(pl); + } + | + arrayer(&count) + {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);} + ]* +| + pointer(&qual) abstract_declarator(dc) + {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);} +; + +%first first_of_parameter_type_list, parameter_type_list; + +primary_abstract_declarator(struct declarator *dc;) +: +[%if (AHEAD == ')' || first_of_parameter_type_list(AHEAD)) + /* empty */ +| + '(' abstract_declarator(dc) ')' +] +; + +parameter_type_list(struct proto **plp;) + { int save_level; } +: + { if (level > L_PROTO) { + save_level = level; + level = L_PROTO; + } else level--; + } + parameter_decl_list(plp) + [ + ',' ELLIPSIS + { register struct proto *new = new_proto(); + + new->next = *plp; + new->pl_flag = PL_ELLIPSIS; + *plp = new; + } + + ]? + { check_for_void(*plp); + if (level == L_PROTO) + level = save_level; + else level++; + } +; + +parameter_decl_list(struct proto **plp;) +: + parameter_decl(plp) + [ %while (AHEAD != ELLIPSIS) + %persistent + ',' parameter_decl(plp) + ]* +; + +parameter_decl(struct proto **plp;) + { register struct proto *new = new_proto(); + struct declarator Dc; + struct decspecs Ds; + } +: + { Dc = null_declarator; + Ds = null_decspecs; + } + decl_specifiers(&Ds) + parameter_declarator(&Dc) + { add_proto(new, &Ds, &Dc, level); + new->next = *plp; + *plp = new; + remove_declarator(&Dc); + } +; + +/* This is weird. Due to the LR structure of the ANSI C grammar + we have to duplicate the actions of 'declarator' and + 'abstract_declarator'. Calling these separately, as in + + parameter_decl: + decl_specifiers + [ + declarator + | + abstract_declarator + ] + + + gives us a conflict on the terminals '(' and '*'. E.i. on + some input, it is impossible to decide which rule we take. + Combining the two declarators into one common declarator + is out of the question, since this results in an empty + string for the non-terminal 'declarator'. + So we combine the two only for the use of parameter_decl, + since this is the only place where they don't give + conflicts. However, this makes the grammar messy. +*/ +parameter_declarator(register struct declarator *dc;) + { struct formal *fm = NO_PARAMS; + struct proto *pl = NO_PROTO; + arith count; + int qual; + } +: + primary_parameter_declarator(dc) + [ + '(' + [ %if (DOT != IDENTIFIER) + parameter_type_list(&pl) + | + formal_list(&fm) + | + /* empty */ + ] + ')' + { add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl); + reject_params(dc); + } + | + arrayer(&count) + {add_decl_unary(dc, ARRAY, 0, count, NO_PARAMS, NO_PROTO);} + ]* +| + pointer(&qual) parameter_declarator(dc) + {add_decl_unary(dc, POINTER, qual, (arith)0, NO_PARAMS, NO_PROTO);} +; + +primary_parameter_declarator(register struct declarator *dc;) +: +[%if (AHEAD == ')' || first_of_parameter_type_list(AHEAD) + && (AHEAD != IDENTIFIER)) + /* empty */ +| + identifier(&dc->dc_idf) +| + '(' parameter_declarator(dc) ')' +] +; + +pointer(int *qual;) +: + '*' type_qualifier_list(qual) +; + +/* Type qualifiers may come in three flavours: + volatile, const, const volatile. + These all have different semantic properties: + + volatile: + means that the object can be modified + without prior knowledge of the implementation. + + const: + means that the object can not be modified; thus + it's illegal to use this as a l-value. + + const volatile: + means that the object can be modified without + prior knowledge of the implementation, but may + not be used as a l-value. +*/ +/* 3.5.4 */ +type_qualifier_list(int *qual;) +: + { *qual = 0; } + [ + VOLATILE + { if (*qual & TQ_VOLATILE) + error("repeated type qualifier"); + *qual |= TQ_VOLATILE; + } + | + CONST + { if (*qual & TQ_CONST) + error("repeated type qualifier"); + *qual |= TQ_CONST; + } + ]* +; + +empty: +; diff --git a/lang/cem/cemcom.ansi/expression.g b/lang/cem/cemcom.ansi/expression.g index 0998883c1..06bd74bc1 100644 --- a/lang/cem/cemcom.ansi/expression.g +++ b/lang/cem/cemcom.ansi/expression.g @@ -1,354 +1,354 @@ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -/* $Id$ */ -/* EXPRESSION SYNTAX PARSER */ - -{ -#include -#include "parameters.h" -#include -#include "arith.h" -#include "LLlex.h" -#include "type.h" -#include "label.h" -#include "expr.h" -#include "code.h" -#include "error.h" -#include "ch3.h" -#include "ch3bin.h" -#include "ch3mon.h" -#include "proto.h" -#include "sizes.h" - -extern struct expr *intexpr(); -int InSizeof = 0; /* inside a sizeof- expression */ -int ResultKnown = 0; /* result of the expression is already known */ - -/* Since the grammar in the standard is not LL(n), it is modified so that - * it accepts basically the same grammar. This means that there is no 1-1 - * mapping from the grammar in the standard to the grammar given here. - * Such is life. - */ -} - -/* 3.3.1 */ -primary(register struct expr **expp;) : - IDENTIFIER - {dot2expr(expp);} -| - constant(expp) -| - string(expp) -| - '(' expression(expp) ')' - { (*expp)->ex_flags |= EX_PARENS; } -; - - -/* Character string literals that are adjacent tokens - * are concatenated into a single character string - * literal. - */ -string(register struct expr **expp;) - { register int i, len; - register char *str; - register int fund; - } -: - STRING - { str = dot.tk_bts; - len = dot.tk_len; - fund = dot.tk_fund; - } - [ - STRING - { /* A pasted string keeps the type of the first - * string literal. - * The pasting of normal strings and wide - * character strings are stated as having an - * undefined behaviour. - */ - if (dot.tk_fund != fund) - warning("illegal pasting of string literals"); - str = Realloc(str, (unsigned) (--len + dot.tk_len)); - for (i = 0; i < dot.tk_len; i++) - str[len++] = dot.tk_bts[i]; - } - ]* - { string2expr(expp, str, len); } -; - -/* 3.3.2 */ -postfix_expression(register struct expr **expp;) - { int oper; - struct expr *e1 = 0; - struct idf *idf; - } -: - primary(expp) - [ - '[' expression(&e1) ']' - { ch3bin(expp, '[', e1); e1 = 0; } - | - '(' parameter_list(&e1)? ')' - { ch3bin(expp, '(', e1); call_proto(expp); e1 = 0; } - | - [ '.' | ARROW ] { oper = DOT; } - identifier(&idf) { ch3sel(expp, oper, idf); } - | - [ - PLUSPLUS { oper = POSTINCR; } - | - MINMIN { oper = POSTDECR; } - ] - { ch3incr(expp, oper); } - ]* -; - -parameter_list(struct expr **expp;) - {struct expr *e1 = 0;} -: - assignment_expression(expp) - {any2opnd(expp, PARCOMMA);} - [ %persistent - ',' - assignment_expression(&e1) - {any2opnd(&e1, PARCOMMA);} - {ch3bin(expp, PARCOMMA, e1);} - ]* -; - -%first first_of_type_specifier, type_specifier; - -/* 3.3.3 & 3.3.4 */ -unary(register struct expr **expp;) - {struct type *tp; int oper;} -: -%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) - cast(&tp) unary(expp) - { ch3cast(expp, CAST, tp); - (*expp)->ex_flags |= EX_CAST; - if (int_size != pointer_size) - (*expp)->ex_flags &= ~EX_PTRDIFF; - } -| - postfix_expression(expp) -| - unop(&oper) unary(expp) - {ch3mon(oper, expp);} -| - size_of(expp) -; - -/* When an identifier is used in a sizeof()-expression, we must stil not - * mark it as used. - * extern int i; .... sizeof(i) .... need not have a definition for i - */ -size_of(register struct expr **expp;) - {struct type *tp;} -: - SIZEOF { InSizeof++; } /* handle (sizeof(sizeof(int))) too */ - [%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) - cast(&tp) - { - *expp = intexpr(size_of_type(tp, "type"), UNSIGNED); - (*expp)->ex_flags |= EX_SIZEOF; - } - | - unary(expp) - {ch3mon(SIZEOF, expp);} - ] - { InSizeof--; } -; - -/* 3.3.5-3.3.17 */ -/* The set of operators in C is stratified in 15 levels, with level - N being treated in RM 7.N (although this is not the standard - anymore). The standard describes this in phrase-structure-grammar, - which we are unable to parse. The description that follows comes - from the old C-compiler. - - In principle each operator is assigned a rank, ranging - from 1 to 15. Such an expression can be parsed by a construct - like: - binary_expression(int maxrank;) - {int oper;} - : - binary_expression(maxrank - 1) - [%if (rank_of(DOT) <= maxrank) - binop(&oper) - binary_expression(rank_of(oper)-1) - ]? - ; - except that some call of 'unary' is necessary, depending on the - grammar. - - This simple view is marred by three complications: - 1. Level 15 (comma operator) is not allowed in many - contexts and is different. - 2. Level 13 (conditional operator) is a ternary operator, - which does not fit this scheme at all. - 3. Level 14 (assignment operators) group right-to-left, as - opposed to 2-12, which group left-to-right (or are - immaterial). - 4. The operators in level 14 start with operators in levels - 2-13 (RM 7.14: The two parts of a compound assignment - operator are separate tokens.) This causes LL1 problems. - This forces us to have four rules: - binary_expression for level 2-12 - conditional_expression for level 13 - assignment_expression for level 14 and - expression for the most general expression -*/ - -binary_expression(int maxrank; struct expr **expp;) - {int oper, OldResultKnown; struct expr *e1;} -: - unary(expp) - [%while (rank_of(DOT) <= maxrank ) - /* '?', '=', and ',' are no binops - */ - binop(&oper) - { OldResultKnown = ResultKnown; - if (oper == OR || oper == AND) { - if (is_cp_cst(*expp) || is_fp_cst(*expp)) { - if (is_zero_cst(*expp)) { - if (oper == AND) ResultKnown++; - } else if (oper == OR) ResultKnown++; - } - } - } - binary_expression(rank_of(oper)-1, &e1) - { - ch3bin(expp, oper, e1); - ResultKnown = OldResultKnown; - } - ]* -; - -/* 3.3.15 */ -conditional_expression(struct expr **expp;) - {struct expr *e1 = 0, *e2 = 0; int OldResultKnown, ConstExpr=0;} -: - /* allow all binary operators */ - binary_expression(rank_of('?') - 1, expp) - [ '?' - { OldResultKnown = ResultKnown; - if (is_cp_cst(*expp) || is_fp_cst(*expp)) { - ConstExpr++; - if (is_zero_cst(*expp)) ResultKnown++; - } - } - expression(&e1) - ':' - { if (ConstExpr) { - if (OldResultKnown == ResultKnown) ResultKnown++; - else ResultKnown = OldResultKnown; - } - } - conditional_expression(&e2) - { - ResultKnown = OldResultKnown; - ch3bin(&e1, ':', e2); - opnd2test(expp, '?'); - ch3bin(expp, '?', e1); - } - ]? -; - -/* 3.3.16 */ -assignment_expression(struct expr **expp;) - { int oper; - struct expr *e1 = 0; - } -: - conditional_expression(expp) - [ - asgnop(&oper) - assignment_expression(&e1) - {ch3asgn(expp, oper, e1);} - | - empty /* LLgen artefact ??? */ - ] -; - -/* 3.3.17 */ -expression(struct expr **expp;) - {struct expr *e1;} -: - assignment_expression(expp) - [ ',' - assignment_expression(&e1) - { - ch3bin(expp, ',', e1); - } - ]* -; - -unop(int *oper;) : - ['*' | '&' | '-' | '+' | '!' | '~' | PLUSPLUS | MINMIN] - { if (DOT == '&') DOT = ADDRESSOF; - *oper = DOT; - } -; - -multop: - '*' | '/' | '%' -; - -addop: - '+' | '-' -; - -shiftop: - LEFT | RIGHT -; - -relop: - '<' | '>' | LESSEQ | GREATEREQ -; - -eqop: - EQUAL | NOTEQUAL -; - -arithop: - multop | addop | shiftop -| - '&' | '^' | '|' -; - -binop(int *oper;) : - [ arithop | relop | eqop | AND | OR ] - {*oper = DOT;} -; - -asgnop(register int *oper;): - [ '=' | PLUSAB | MINAB | TIMESAB | DIVAB | MODAB - | LEFTAB | RIGHTAB | ANDAB | XORAB | ORAB ] - { *oper = DOT; } - -; - -constant(struct expr **expp;) : -[ - INTEGER -| - FLOATING -] {dot2expr(expp);} -; - -/* 3.4 */ -constant_expression (struct expr **expp;) : - conditional_expression(expp) - { chk_cst_expr(expp); } -; - -identifier(struct idf **idfp;) : -[ IDENTIFIER -| TYPE_IDENTIFIER -] - { *idfp = dot.tk_idf; } -; +/* + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ +/* $Id$ */ +/* EXPRESSION SYNTAX PARSER */ + +{ +#include +#include "parameters.h" +#include +#include "arith.h" +#include "LLlex.h" +#include "type.h" +#include "label.h" +#include "expr.h" +#include "code.h" +#include "error.h" +#include "ch3.h" +#include "ch3bin.h" +#include "ch3mon.h" +#include "proto.h" +#include "sizes.h" + +extern struct expr *intexpr(); +int InSizeof = 0; /* inside a sizeof- expression */ +int ResultKnown = 0; /* result of the expression is already known */ + +/* Since the grammar in the standard is not LL(n), it is modified so that + * it accepts basically the same grammar. This means that there is no 1-1 + * mapping from the grammar in the standard to the grammar given here. + * Such is life. + */ +} + +/* 3.3.1 */ +primary(register struct expr **expp;) : + IDENTIFIER + {dot2expr(expp);} +| + constant(expp) +| + string(expp) +| + '(' expression(expp) ')' + { (*expp)->ex_flags |= EX_PARENS; } +; + + +/* Character string literals that are adjacent tokens + * are concatenated into a single character string + * literal. + */ +string(register struct expr **expp;) + { register int i, len; + register char *str; + register int fund; + } +: + STRING + { str = dot.tk_bts; + len = dot.tk_len; + fund = dot.tk_fund; + } + [ + STRING + { /* A pasted string keeps the type of the first + * string literal. + * The pasting of normal strings and wide + * character strings are stated as having an + * undefined behaviour. + */ + if (dot.tk_fund != fund) + warning("illegal pasting of string literals"); + str = Realloc(str, (unsigned) (--len + dot.tk_len)); + for (i = 0; i < dot.tk_len; i++) + str[len++] = dot.tk_bts[i]; + } + ]* + { string2expr(expp, str, len); } +; + +/* 3.3.2 */ +postfix_expression(register struct expr **expp;) + { int oper; + struct expr *e1 = 0; + struct idf *idf; + } +: + primary(expp) + [ + '[' expression(&e1) ']' + { ch3bin(expp, '[', e1); e1 = 0; } + | + '(' parameter_list(&e1)? ')' + { ch3bin(expp, '(', e1); call_proto(expp); e1 = 0; } + | + [ '.' | ARROW ] { oper = DOT; } + identifier(&idf) { ch3sel(expp, oper, idf); } + | + [ + PLUSPLUS { oper = POSTINCR; } + | + MINMIN { oper = POSTDECR; } + ] + { ch3incr(expp, oper); } + ]* +; + +parameter_list(struct expr **expp;) + {struct expr *e1 = 0;} +: + assignment_expression(expp) + {any2opnd(expp, PARCOMMA);} + [ %persistent + ',' + assignment_expression(&e1) + {any2opnd(&e1, PARCOMMA);} + {ch3bin(expp, PARCOMMA, e1);} + ]* +; + +%first first_of_type_specifier, type_specifier; + +/* 3.3.3 & 3.3.4 */ +unary(register struct expr **expp;) + {struct type *tp; int oper;} +: +%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) + cast(&tp) unary(expp) + { ch3cast(expp, CAST, tp); + (*expp)->ex_flags |= EX_CAST; + if (int_size != pointer_size) + (*expp)->ex_flags &= ~EX_PTRDIFF; + } +| + postfix_expression(expp) +| + unop(&oper) unary(expp) + {ch3mon(oper, expp);} +| + size_of(expp) +; + +/* When an identifier is used in a sizeof()-expression, we must stil not + * mark it as used. + * extern int i; .... sizeof(i) .... need not have a definition for i + */ +size_of(register struct expr **expp;) + {struct type *tp;} +: + SIZEOF { InSizeof++; } /* handle (sizeof(sizeof(int))) too */ + [%if (first_of_type_specifier(AHEAD) && AHEAD != IDENTIFIER) + cast(&tp) + { + *expp = intexpr(size_of_type(tp, "type"), UNSIGNED); + (*expp)->ex_flags |= EX_SIZEOF; + } + | + unary(expp) + {ch3mon(SIZEOF, expp);} + ] + { InSizeof--; } +; + +/* 3.3.5-3.3.17 */ +/* The set of operators in C is stratified in 15 levels, with level + N being treated in RM 7.N (although this is not the standard + anymore). The standard describes this in phrase-structure-grammar, + which we are unable to parse. The description that follows comes + from the old C-compiler. + + In principle each operator is assigned a rank, ranging + from 1 to 15. Such an expression can be parsed by a construct + like: + binary_expression(int maxrank;) + {int oper;} + : + binary_expression(maxrank - 1) + [%if (rank_of(DOT) <= maxrank) + binop(&oper) + binary_expression(rank_of(oper)-1) + ]? + ; + except that some call of 'unary' is necessary, depending on the + grammar. + + This simple view is marred by three complications: + 1. Level 15 (comma operator) is not allowed in many + contexts and is different. + 2. Level 13 (conditional operator) is a ternary operator, + which does not fit this scheme at all. + 3. Level 14 (assignment operators) group right-to-left, as + opposed to 2-12, which group left-to-right (or are + immaterial). + 4. The operators in level 14 start with operators in levels + 2-13 (RM 7.14: The two parts of a compound assignment + operator are separate tokens.) This causes LL1 problems. + This forces us to have four rules: + binary_expression for level 2-12 + conditional_expression for level 13 + assignment_expression for level 14 and + expression for the most general expression +*/ + +binary_expression(int maxrank; struct expr **expp;) + {int oper, OldResultKnown; struct expr *e1;} +: + unary(expp) + [%while (rank_of(DOT) <= maxrank ) + /* '?', '=', and ',' are no binops + */ + binop(&oper) + { OldResultKnown = ResultKnown; + if (oper == OR || oper == AND) { + if (is_cp_cst(*expp) || is_fp_cst(*expp)) { + if (is_zero_cst(*expp)) { + if (oper == AND) ResultKnown++; + } else if (oper == OR) ResultKnown++; + } + } + } + binary_expression(rank_of(oper)-1, &e1) + { + ch3bin(expp, oper, e1); + ResultKnown = OldResultKnown; + } + ]* +; + +/* 3.3.15 */ +conditional_expression(struct expr **expp;) + {struct expr *e1 = 0, *e2 = 0; int OldResultKnown, ConstExpr=0;} +: + /* allow all binary operators */ + binary_expression(rank_of('?') - 1, expp) + [ '?' + { OldResultKnown = ResultKnown; + if (is_cp_cst(*expp) || is_fp_cst(*expp)) { + ConstExpr++; + if (is_zero_cst(*expp)) ResultKnown++; + } + } + expression(&e1) + ':' + { if (ConstExpr) { + if (OldResultKnown == ResultKnown) ResultKnown++; + else ResultKnown = OldResultKnown; + } + } + conditional_expression(&e2) + { + ResultKnown = OldResultKnown; + ch3bin(&e1, ':', e2); + opnd2test(expp, '?'); + ch3bin(expp, '?', e1); + } + ]? +; + +/* 3.3.16 */ +assignment_expression(struct expr **expp;) + { int oper; + struct expr *e1 = 0; + } +: + conditional_expression(expp) + [ + asgnop(&oper) + assignment_expression(&e1) + {ch3asgn(expp, oper, e1);} + | + empty /* LLgen artefact ??? */ + ] +; + +/* 3.3.17 */ +expression(struct expr **expp;) + {struct expr *e1;} +: + assignment_expression(expp) + [ ',' + assignment_expression(&e1) + { + ch3bin(expp, ',', e1); + } + ]* +; + +unop(int *oper;) : + ['*' | '&' | '-' | '+' | '!' | '~' | PLUSPLUS | MINMIN] + { if (DOT == '&') DOT = ADDRESSOF; + *oper = DOT; + } +; + +multop: + '*' | '/' | '%' +; + +addop: + '+' | '-' +; + +shiftop: + LEFT | RIGHT +; + +relop: + '<' | '>' | LESSEQ | GREATEREQ +; + +eqop: + EQUAL | NOTEQUAL +; + +arithop: + multop | addop | shiftop +| + '&' | '^' | '|' +; + +binop(int *oper;) : + [ arithop | relop | eqop | AND | OR ] + {*oper = DOT;} +; + +asgnop(register int *oper;): + [ '=' | PLUSAB | MINAB | TIMESAB | DIVAB | MODAB + | LEFTAB | RIGHTAB | ANDAB | XORAB | ORAB ] + { *oper = DOT; } + +; + +constant(struct expr **expp;) : +[ + INTEGER +| + FLOATING +] {dot2expr(expp);} +; + +/* 3.4 */ +constant_expression (struct expr **expp;) : + conditional_expression(expp) + { chk_cst_expr(expp); } +; + +identifier(struct idf **idfp;) : +[ IDENTIFIER +| TYPE_IDENTIFIER +] + { *idfp = dot.tk_idf; } +; diff --git a/lang/cem/cemcom.ansi/ival.g b/lang/cem/cemcom.ansi/ival.g index 05fcc4881..2e9d3d878 100644 --- a/lang/cem/cemcom.ansi/ival.g +++ b/lang/cem/cemcom.ansi/ival.g @@ -1,760 +1,760 @@ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -/* $Id$ */ -/* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */ - -{ -#include -#include -#include "parameters.h" -#ifndef LINT -#include -#else -#include "l_em.h" -#include "l_lint.h" -#endif /* LINT */ -#include -#include -#include -#include -#include -#include "idf.h" -#include "arith.h" -#include "label.h" -#include "expr.h" -#include "type.h" -#include "proto.h" -#include "struct.h" -#include "field.h" -#include "Lpars.h" -#include "sizes.h" -#include "align.h" -#include "level.h" -#include "error.h" -#include "def.h" -#include "LLlex.h" -#include "estack.h" -#include "stack.h" -#include "ch3.h" - -#define con_nullbyte() C_con_ucon("0", (arith)1) -#define aggregate_type(tp) ((tp)->tp_fund == ARRAY || (tp)->tp_fund == STRUCT) - -extern char options[]; -static int gen_error; -static int pack_level; -struct e_stack *p_stack; - -void gen_tpcheck(struct type **); -void gen_simple_exp(struct type **, struct expr **); -struct type **arr_elem(struct type **, struct e_stack *); -struct sdef *next_field(register struct sdef *,register struct e_stack *); -struct type **gen_tphead(struct type **, int); -struct type **gen_tpmiddle(void); -struct sdef *gen_align_to_next(register struct e_stack *); -void gen_tpend(void); -void check_and_pad(struct expr **, struct type **); -void pad(struct type *); -void check_ival(struct expr **, register struct type *); -void ch_array(struct type **, /* type tp = array of characters */ - struct expr *); -void str_cst(register char *, register int, int); -#ifndef NOBITFIELD -void put_bf(struct type *, arith ); -#endif /* NOBITFIELD */ -int zero_bytes(register struct sdef *); -int valid_type(struct type *, char *); -void con_int(register struct expr *); -void illegal_init_cst(struct expr *); -void too_many_initialisers(void); - -} - -/* initial_value recursively guides the initialisation expression. - */ -/* 3.5 */ - -initial_value(register struct type **tpp; register struct expr **expp;) : - { if (tpp) gen_tpcheck(tpp); } -[ - { if (pack_level == 0) gen_error = 0; } - assignment_expression(expp) - { -#ifdef LINT - lint_expr(*expp, USED); -#endif /* LINT */ - if ((*expp)->ex_type->tp_fund == ARRAY) - array2pointer(*expp); - if (tpp) { - if (level >= L_LOCAL - || is_ld_cst(*expp) - || is_fp_cst(*expp) - || (*expp)->ex_class == String) { - gen_simple_exp(tpp, expp); - free_expression(*expp); - *expp = 0; - } else { - expr_error(*expp,"illegal initialization"); - free_expression(*expp); - *expp = 0; - } - } - } -| - initial_value_pack(tpp, expp) -] -; - -initial_value_pack(struct type **tpp; struct expr **expp;) -: - '{' - { if (pack_level == 0) gen_error = 0; pack_level++; } - initial_value_list(tpp, expp) - { pack_level--; - if (!pack_level) { - while (p_stack) { - struct e_stack *p = p_stack->next; - - free_e_stack(p_stack); - p_stack = p; - } - } - if (pack_level < gen_error) gen_error = 0; - } - '}' -; - -initial_value_list(register struct type **tpp; struct expr **expp;) - { struct expr *e1; - register struct type **tpp2 = 0; - int err_flag = gen_error; - } -: - { if (tpp) tpp2 = gen_tphead(tpp, 0); } - initial_value(tpp2, &e1) - { if (!tpp) init_expression(&expp, e1); } - [%while (AHEAD != '}') /* >>> conflict on ',' */ - ',' - { if (tpp) tpp2 = gen_tpmiddle(); } - initial_value(tpp2, &e1) - { if (!tpp) init_expression(&expp, e1); } - ]* - { if (tpp && ! err_flag) gen_tpend(); } - ','? /* optional trailing comma */ -; - -{ -void gen_tpcheck(struct type **tpp) -{ - register struct type *tp; - - if (gen_error) return; - switch((tp = *tpp)->tp_fund) { - case ARRAY: - if (! valid_type(tp->tp_up, "array element")) - gen_error = pack_level; - break; - case STRUCT: - if (! valid_type(tp, "struct")) - gen_error = pack_level; - break; - case UNION: - if (! valid_type(tp, "union")) - gen_error = pack_level; - break; - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - break; - } -} - -void gen_simple_exp(struct type **tpp, struct expr **expp) -{ - register struct type *tp; - - if (gen_error) return; - tp = *tpp; - switch(tp->tp_fund) { - case ARRAY: - if ((*expp)->ex_class == String && tp->tp_up->tp_fund == CHAR) { - ch_array(tpp,*expp); - break; - } - /* Fall through */ - case UNION: - case STRUCT: - check_and_pad(expp, tpp); - break; - case ERRONEOUS: - case FUNCTION: - case VOID: - gen_error = pack_level; - break; - default: - check_ival(expp, tp); - break; - } -} - -struct type **arr_elem(struct type **tpp, struct e_stack *p) -{ - register struct type *tp = *tpp; - - if (tp->tp_up->tp_fund == CHAR && AHEAD == STRING && p->elem_count == 1) { - p->nelem = 1; - return tpp; - } - if (AHEAD == '{' || (! aggregate_type(tp->tp_up) && tp->tp_up->tp_fund != UNION)) - return &(tp->tp_up); - return gen_tphead(&(tp->tp_up), 1); -} - -struct sdef *next_field(register struct sdef *sd, - register struct e_stack *p) -{ - if (sd->sd_sdef) - p->bytes_upto_here += zero_bytes(sd); - p->bytes_upto_here += - size_of_type(sd->sd_type, "selector"); - p->last_offset = sd->sd_offset; - return sd->sd_sdef; -} - -struct type **gen_tphead(struct type **tpp, int nest) -{ - register struct type *tp = *tpp; - register struct e_stack *p; - register struct sdef *sd; - - if (tpp && *tpp == error_type) { - gen_error = pack_level; - return 0; - } - if (gen_error) return tpp; - if (tp->tp_fund == UNION) { - /* Here, we saw a {, which could be the start of a union - initializer. It could, however, also be the start of the - initializer for the first union field ... - */ - sd = tp->tp_sdef; - if (AHEAD != '{' && - (aggregate_type(sd->sd_type) || - sd->sd_type->tp_fund == UNION)) { - /* In this case, assume that it is the start of the - initializer of the union field, so: - */ - return gen_tphead(&(tp->tp_sdef->sd_type), nest); - } - } - p = new_e_stack(); - p->next = p_stack; - p_stack = p; - p->s_nested = nest; - p->s_tpp = tpp; - switch(tp->tp_fund) { - case UNION: - p->s_def = sd = tp->tp_sdef; - p->bytes_upto_here = 0; - return &(sd->sd_type); - case ARRAY: - p->nelem = -1; - p->elem_count = 1; - if (tp->tp_size != (arith) -1) { - p->nelem = (tp->tp_size / tp->tp_up->tp_size); - } - return arr_elem(tpp, p); - case STRUCT: - p->s_def = sd = tp->tp_sdef; - p->bytes_upto_here = 0; - p->last_offset = -1; -#ifndef NOBITFIELD - while (sd && is_anon_idf(sd->sd_idf)) { - put_bf(sd->sd_type, (arith) 0); - sd = next_field(sd, p); - } -#endif - if (! sd) { - /* something wrong with this struct */ - gen_error = pack_level; - p_stack = p->next; - free_e_stack(p); - return 0; - } - p->s_def = sd; - if (AHEAD != '{' && aggregate_type(sd->sd_type)) { - return gen_tphead(&(sd->sd_type), 1); - } - return &(sd->sd_type); - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - /* fall through */ - default: - p->nelem = 1; - p->elem_count = 1; - return tpp; - } -} - -struct type **gen_tpmiddle(void) -{ - register struct type *tp; - register struct sdef *sd; - register struct e_stack *p = p_stack; - - if (gen_error) { - if (p) return p->s_tpp; - return 0; - } -again: - tp = *(p->s_tpp); - switch(tp->tp_fund) { - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - return p->s_tpp; - case UNION: - sd = p->s_def; - p->bytes_upto_here += - size_of_type(sd->sd_type, "selector"); - return p->s_tpp; - default: - if (p->elem_count == p->nelem && p->s_nested) { - p = p->next; - free_e_stack(p_stack); - p_stack = p; - goto again; - } - p->elem_count++; - if (p->nelem >= 0 && p->elem_count > p->nelem) { - too_many_initialisers(); - return p->s_tpp; - } - if (tp->tp_fund == ARRAY) { - return arr_elem(p->s_tpp, p); - } - return p->s_tpp; - case STRUCT: - sd = gen_align_to_next(p); - if (! sd) { - while (p->bytes_upto_here++ < tp->tp_size) - con_nullbyte(); - if (p->s_nested) { - p = p->next; - free_e_stack(p_stack); - p_stack = p; - goto again; - } - too_many_initialisers(); - return p->s_tpp; - } - if (AHEAD != '{' && aggregate_type(sd->sd_type)) { - return gen_tphead(&(sd->sd_type), 1); - } - return &(sd->sd_type); - } -} - -struct sdef *gen_align_to_next(register struct e_stack *p) -{ - register struct sdef *sd = p->s_def; - - if (! sd) return sd; -#ifndef NOBITFIELD - do { - if (is_anon_idf(sd->sd_idf)) put_bf(sd->sd_type, (arith) 0); -#endif - sd = next_field(sd, p); -#ifndef NOBITFIELD - } while (sd && is_anon_idf(sd->sd_idf)); -#endif - p->s_def = sd; - return sd; -} - -void gen_tpend(void) -{ - register struct e_stack *p = p_stack; - register struct type *tp; - register struct sdef *sd; - int getout = 0; - - while (!getout && p) { - if (!gen_error) { - tp = *(p->s_tpp); - switch(tp->tp_fund) { - case UNION: - sd = p->s_def; - p->bytes_upto_here += - size_of_type(sd->sd_type, "selector"); - while (p->bytes_upto_here++ < tp->tp_size) - con_nullbyte(); - break; - case ARRAY: - if (tp->tp_size == -1) { - *(p->s_tpp) = construct_type(ARRAY, tp->tp_up, - 0, p->elem_count, NO_PROTO); - } - else { - while (p->nelem-- > p->elem_count) { - pad(tp->tp_up); - } - } - break; - case STRUCT: - sd = gen_align_to_next(p); - while (sd) { - pad(sd->sd_type); - if (sd->sd_sdef) - p->bytes_upto_here += zero_bytes(sd); - p->bytes_upto_here += - size_of_type(sd->sd_type, "selector"); - sd = sd->sd_sdef; - } - while (p->bytes_upto_here++ < tp->tp_size) - con_nullbyte(); - break; - } - } - if (! p->s_nested) getout = 1; - p = p->next; - free_e_stack(p_stack); - p_stack = p; - } -} - -/* check_and_pad() is given a simple initialisation expression - where the type can be either a simple or an aggregate type. - In the latter case, only the first member is initialised and - the rest is zeroed. -*/ -void check_and_pad(struct expr **expp, struct type **tpp) -{ - register struct type *tp = *tpp; - - if (tp->tp_fund == ARRAY) { - check_and_pad(expp, &(tp->tp_up)); /* first member */ - if (tp->tp_size == (arith)-1) - /* no size specified upto here: just - set it to the size of one member. - */ - tp = *tpp = construct_type(ARRAY, tp->tp_up, - 0, (arith)1, NO_PROTO); - else { - register int dim = tp->tp_size / tp->tp_up->tp_size; - /* pad remaining members with zeroes */ - while (--dim > 0) - pad(tp->tp_up); - } - } - else - if (tp->tp_fund == STRUCT) { - register struct sdef *sd = tp->tp_sdef; - - check_and_pad(expp, &(sd->sd_type)); - /* next selector is aligned by adding extra zeroes */ - if (sd->sd_sdef) - zero_bytes(sd); - while ( (sd = sd->sd_sdef)!=0) { /* pad remaining selectors */ - pad(sd->sd_type); - if (sd->sd_sdef) - zero_bytes(sd); - } - } - else if (tp->tp_fund == UNION) { - /* only the first selector can be initialized */ - register struct sdef *sd = tp->tp_sdef; - - check_and_pad(expp, &(sd->sd_type)); - } - else /* simple type */ - check_ival(expp, tp); -} - -/* pad() fills an element of type tp with zeroes. - If the element is an aggregate, pad() is called recursively. -*/ -void pad(struct type *tpx) -{ - register struct type *tp = tpx; - register arith sz = tp->tp_size; - - gen_tpcheck(&tpx); - if (gen_error) return; -#ifndef NOBITFIELD - if (tp->tp_fund == FIELD) { - put_bf(tp, (arith)0); - return; - } -#endif /* NOBITFIELD */ - - if (tp->tp_align >= word_align) while (sz >= word_size) { - C_con_cst((arith) 0); - sz -= word_size; - } - while (sz) { - C_con_icon("0", (arith) 1); - sz--; - } -} - -/* check_ival() checks whether the initialisation of an element - of a fundamental type is legal and, if so, performs the initialisation - by directly generating the necessary code. - No further comment is needed to explain the internal structure - of this straightforward function. -*/ -void check_ival(struct expr **expp, register struct type *tp) -{ - /* The philosophy here is that ch3cast puts an explicit - conversion node in front of the expression if the types - are not compatible. In this case, the initialisation - expression is no longer a constant. - */ - register struct expr *expr = *expp; - - switch (tp->tp_fund) { - case CHAR: - case SHORT: - case INT: - case LONG: - case LNGLNG: - case ENUM: - case POINTER: - ch3cast(expp, '=', tp); - expr = *expp; -#ifdef DEBUG - print_expr("init-expr after cast", expr); -#endif /* DEBUG */ - if (!is_ld_cst(expr)) - illegal_init_cst(expr); - else - if (expr->VL_CLASS == Const) - con_int(expr); - else - if (expr->VL_CLASS == Name) { - register struct idf *idf = expr->VL_IDF; - - if (idf->id_def->df_level >= L_LOCAL - && idf->id_def->df_sc != GLOBAL - && idf->id_def->df_sc != EXTERN) { - illegal_init_cst(expr); - } - else /* e.g., int f(); int p = f; */ - if (idf->id_def->df_type->tp_fund == FUNCTION) - C_con_pnam(idf->id_text); - else /* e.g., int a; int *p = &a; */ - C_con_dnam(idf->id_text, (arith)expr->VL_VALUE); - } - else { - assert(expr->VL_CLASS == Label); - C_con_dlb(expr->VL_LBL, (arith)expr->VL_VALUE); - } - break; - case FLOAT: - case DOUBLE: - case LNGDBL: - ch3cast(expp, '=', tp); - expr = *expp; -#ifdef DEBUG - print_expr("init-expr after cast", expr); -#endif /* DEBUG */ - if (expr->ex_class == Float) { - char buf[FLT_STRLEN]; - - flt_flt2str(&(expr->FL_ARITH), buf, FLT_STRLEN); - C_con_fcon(buf, expr->ex_type->tp_size); - } -#ifdef NOTDEF - -Coercion from int to float is now always done compile time. -This, to accept declarations like -double x = -(double)1; -and also to prevent runtime coercions for compile-time constants. - - else - if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) { - /* float f = 1; */ - expr = expr->OP_RIGHT; - if (is_cp_cst(expr)) - C_con_fcon(long2str((long)expr->VL_VALUE, 10), - tp->tp_size); - else - illegal_init_cst(expr); - } -#endif /* NOTDEF */ - else - illegal_init_cst(expr); - break; - -#ifndef NOBITFIELD - case FIELD: - ch3cast(expp, '=', tp->tp_up); - expr = *expp; -#ifdef DEBUG - print_expr("init-expr after cast", expr); -#endif /* DEBUG */ - if (is_cp_cst(expr)) - put_bf(tp, (arith)expr->VL_VALUE); - else - illegal_init_cst(expr); - break; -#endif /* NOBITFIELD */ - - case ERRONEOUS: - if (! gen_error) gen_error = pack_level; - /* fall through */ - case VOID: - break; - default: - crash("check_ival"); - /*NOTREACHED*/ - } -} - -/* ch_array() initialises an array of characters when given - a string constant. - Alignment is taken care of. -*/ -void ch_array(struct type **tpp, /* type tp = array of characters */ - struct expr *ex) -{ - register struct type *tp = *tpp; - register int length = ex->SG_LEN, i; - register char *to, *from, *s; - - assert(ex->ex_class == String); - if (tp->tp_size == (arith)-1) { - /* set the dimension */ - tp = *tpp = construct_type(ARRAY, tp->tp_up, 0, (arith)length, NO_PROTO); - } - else { - arith dim = tp->tp_size / tp->tp_up->tp_size; - -#ifdef LINT - if (length == dim + 1) { - expr_warning(ex, "array is not null-terminated"); - } else -#endif - if (length > dim + 1) { - expr_strict(ex, "too many initializers"); - } - length = dim; - } - /* throw out the characters of the already prepared string */ - s = Malloc((unsigned) (length)); - clear(s, (unsigned)length); - i = length <= ex->SG_LEN ? length : ex->SG_LEN; - to = s; from = ex->SG_VALUE; - while(--i >= 0) { - *to++ = *from++; - } - free(ex->SG_VALUE); - str_cst(s, length, 0); /* a string, but not in rom */ - free(s); -} - -/* As long as some parts of the pipeline cannot handle very long string - constants, string constants are written out in chunks -*/ -void str_cst(register char *str, register int len, int inrom) -{ - int chunksize = ((127 + (int) word_size) / (int) word_size) * (int) word_size; - - while (len > chunksize) { - if (inrom) - C_rom_scon(str, (arith) chunksize); - else C_con_scon(str, (arith) chunksize); - len -= chunksize; - str += chunksize; - } - if (inrom) - C_rom_scon(str, (arith) len); - else C_con_scon(str, (arith) len); -} - -#ifndef NOBITFIELD -/* put_bf() takes care of the initialisation of (bit-)field - selectors of a struct: each time such an initialisation takes place, - put_bf() is called instead of the normal code generating routines. - Put_bf() stores the given integral value into "field" and - "throws" the result of "field" out if the current selector - is the last of this number of fields stored at the same address. -*/ -void put_bf(struct type *tp, arith val) -{ - static long field = (arith)0; - static arith offset = (arith)-1; - register struct field *fd = tp->tp_field; - register struct sdef *sd = fd->fd_sdef; - static struct expr exp; - - assert(sd); - if (offset == (arith)-1) { - /* first bitfield in this field */ - offset = sd->sd_offset; - exp.ex_type = tp->tp_up; - exp.ex_class = Value; - exp.VL_CLASS = Const; - } - if (val != 0) /* insert the value into "field" */ - field |= (val & fd->fd_mask) << fd->fd_shift; - if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) { - /* the selector was the last stored at this address */ - exp.VL_VALUE = (writh)field; - con_int(&exp); - field = (arith)0; - offset = (arith)-1; - } -} -#endif /* NOBITFIELD */ - -int zero_bytes(register struct sdef *sd) -{ - /* fills the space between a selector of a struct - and the next selector of that struct with zero-bytes. - */ - register int n = sd->sd_sdef->sd_offset - sd->sd_offset - - size_of_type(sd->sd_type, "struct member"); - int count = n; - - while (n-- > 0) - con_nullbyte(); - return count; -} - -int valid_type(struct type *tp, char *str) -{ - assert(tp!=(struct type *)0); - if (tp->tp_size < 0) { - error("size of %s unknown", str); - return 0; - } - return 1; -} - -void con_int(register struct expr *ex) -{ - register struct type *tp = ex->ex_type; - - assert(is_cp_cst(ex)); - if (tp->tp_unsigned) - C_con_ucon(writh2str(ex->VL_VALUE, 1), tp->tp_size); - else if (tp->tp_size == word_size) - C_con_cst((arith)ex->VL_VALUE); - else - C_con_icon(writh2str(ex->VL_VALUE, 0), tp->tp_size); -} - -void illegal_init_cst(struct expr *ex) -{ - expr_error(ex, "illegal initialization constant"); - gen_error = pack_level; -} - -void too_many_initialisers(void) -{ - error("too many initializers"); - gen_error = pack_level; -} -} +/* + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ +/* $Id$ */ +/* CODE FOR THE INITIALISATION OF GLOBAL VARIABLES */ + +{ +#include +#include +#include "parameters.h" +#ifndef LINT +#include +#else +#include "l_em.h" +#include "l_lint.h" +#endif /* LINT */ +#include +#include +#include +#include +#include +#include "idf.h" +#include "arith.h" +#include "label.h" +#include "expr.h" +#include "type.h" +#include "proto.h" +#include "struct.h" +#include "field.h" +#include "Lpars.h" +#include "sizes.h" +#include "align.h" +#include "level.h" +#include "error.h" +#include "def.h" +#include "LLlex.h" +#include "estack.h" +#include "stack.h" +#include "ch3.h" + +#define con_nullbyte() C_con_ucon("0", (arith)1) +#define aggregate_type(tp) ((tp)->tp_fund == ARRAY || (tp)->tp_fund == STRUCT) + +extern char options[]; +static int gen_error; +static int pack_level; +struct e_stack *p_stack; + +void gen_tpcheck(struct type **); +void gen_simple_exp(struct type **, struct expr **); +struct type **arr_elem(struct type **, struct e_stack *); +struct sdef *next_field(register struct sdef *,register struct e_stack *); +struct type **gen_tphead(struct type **, int); +struct type **gen_tpmiddle(void); +struct sdef *gen_align_to_next(register struct e_stack *); +void gen_tpend(void); +void check_and_pad(struct expr **, struct type **); +void pad(struct type *); +void check_ival(struct expr **, register struct type *); +void ch_array(struct type **, /* type tp = array of characters */ + struct expr *); +void str_cst(register char *, register int, int); +#ifndef NOBITFIELD +void put_bf(struct type *, arith ); +#endif /* NOBITFIELD */ +int zero_bytes(register struct sdef *); +int valid_type(struct type *, char *); +void con_int(register struct expr *); +void illegal_init_cst(struct expr *); +void too_many_initialisers(void); + +} + +/* initial_value recursively guides the initialisation expression. + */ +/* 3.5 */ + +initial_value(register struct type **tpp; register struct expr **expp;) : + { if (tpp) gen_tpcheck(tpp); } +[ + { if (pack_level == 0) gen_error = 0; } + assignment_expression(expp) + { +#ifdef LINT + lint_expr(*expp, USED); +#endif /* LINT */ + if ((*expp)->ex_type->tp_fund == ARRAY) + array2pointer(*expp); + if (tpp) { + if (level >= L_LOCAL + || is_ld_cst(*expp) + || is_fp_cst(*expp) + || (*expp)->ex_class == String) { + gen_simple_exp(tpp, expp); + free_expression(*expp); + *expp = 0; + } else { + expr_error(*expp,"illegal initialization"); + free_expression(*expp); + *expp = 0; + } + } + } +| + initial_value_pack(tpp, expp) +] +; + +initial_value_pack(struct type **tpp; struct expr **expp;) +: + '{' + { if (pack_level == 0) gen_error = 0; pack_level++; } + initial_value_list(tpp, expp) + { pack_level--; + if (!pack_level) { + while (p_stack) { + struct e_stack *p = p_stack->next; + + free_e_stack(p_stack); + p_stack = p; + } + } + if (pack_level < gen_error) gen_error = 0; + } + '}' +; + +initial_value_list(register struct type **tpp; struct expr **expp;) + { struct expr *e1; + register struct type **tpp2 = 0; + int err_flag = gen_error; + } +: + { if (tpp) tpp2 = gen_tphead(tpp, 0); } + initial_value(tpp2, &e1) + { if (!tpp) init_expression(&expp, e1); } + [%while (AHEAD != '}') /* >>> conflict on ',' */ + ',' + { if (tpp) tpp2 = gen_tpmiddle(); } + initial_value(tpp2, &e1) + { if (!tpp) init_expression(&expp, e1); } + ]* + { if (tpp && ! err_flag) gen_tpend(); } + ','? /* optional trailing comma */ +; + +{ +void gen_tpcheck(struct type **tpp) +{ + register struct type *tp; + + if (gen_error) return; + switch((tp = *tpp)->tp_fund) { + case ARRAY: + if (! valid_type(tp->tp_up, "array element")) + gen_error = pack_level; + break; + case STRUCT: + if (! valid_type(tp, "struct")) + gen_error = pack_level; + break; + case UNION: + if (! valid_type(tp, "union")) + gen_error = pack_level; + break; + case ERRONEOUS: + if (! gen_error) gen_error = pack_level; + break; + } +} + +void gen_simple_exp(struct type **tpp, struct expr **expp) +{ + register struct type *tp; + + if (gen_error) return; + tp = *tpp; + switch(tp->tp_fund) { + case ARRAY: + if ((*expp)->ex_class == String && tp->tp_up->tp_fund == CHAR) { + ch_array(tpp,*expp); + break; + } + /* Fall through */ + case UNION: + case STRUCT: + check_and_pad(expp, tpp); + break; + case ERRONEOUS: + case FUNCTION: + case VOID: + gen_error = pack_level; + break; + default: + check_ival(expp, tp); + break; + } +} + +struct type **arr_elem(struct type **tpp, struct e_stack *p) +{ + register struct type *tp = *tpp; + + if (tp->tp_up->tp_fund == CHAR && AHEAD == STRING && p->elem_count == 1) { + p->nelem = 1; + return tpp; + } + if (AHEAD == '{' || (! aggregate_type(tp->tp_up) && tp->tp_up->tp_fund != UNION)) + return &(tp->tp_up); + return gen_tphead(&(tp->tp_up), 1); +} + +struct sdef *next_field(register struct sdef *sd, + register struct e_stack *p) +{ + if (sd->sd_sdef) + p->bytes_upto_here += zero_bytes(sd); + p->bytes_upto_here += + size_of_type(sd->sd_type, "selector"); + p->last_offset = sd->sd_offset; + return sd->sd_sdef; +} + +struct type **gen_tphead(struct type **tpp, int nest) +{ + register struct type *tp = *tpp; + register struct e_stack *p; + register struct sdef *sd; + + if (tpp && *tpp == error_type) { + gen_error = pack_level; + return 0; + } + if (gen_error) return tpp; + if (tp->tp_fund == UNION) { + /* Here, we saw a {, which could be the start of a union + initializer. It could, however, also be the start of the + initializer for the first union field ... + */ + sd = tp->tp_sdef; + if (AHEAD != '{' && + (aggregate_type(sd->sd_type) || + sd->sd_type->tp_fund == UNION)) { + /* In this case, assume that it is the start of the + initializer of the union field, so: + */ + return gen_tphead(&(tp->tp_sdef->sd_type), nest); + } + } + p = new_e_stack(); + p->next = p_stack; + p_stack = p; + p->s_nested = nest; + p->s_tpp = tpp; + switch(tp->tp_fund) { + case UNION: + p->s_def = sd = tp->tp_sdef; + p->bytes_upto_here = 0; + return &(sd->sd_type); + case ARRAY: + p->nelem = -1; + p->elem_count = 1; + if (tp->tp_size != (arith) -1) { + p->nelem = (tp->tp_size / tp->tp_up->tp_size); + } + return arr_elem(tpp, p); + case STRUCT: + p->s_def = sd = tp->tp_sdef; + p->bytes_upto_here = 0; + p->last_offset = -1; +#ifndef NOBITFIELD + while (sd && is_anon_idf(sd->sd_idf)) { + put_bf(sd->sd_type, (arith) 0); + sd = next_field(sd, p); + } +#endif + if (! sd) { + /* something wrong with this struct */ + gen_error = pack_level; + p_stack = p->next; + free_e_stack(p); + return 0; + } + p->s_def = sd; + if (AHEAD != '{' && aggregate_type(sd->sd_type)) { + return gen_tphead(&(sd->sd_type), 1); + } + return &(sd->sd_type); + case ERRONEOUS: + if (! gen_error) gen_error = pack_level; + /* fall through */ + default: + p->nelem = 1; + p->elem_count = 1; + return tpp; + } +} + +struct type **gen_tpmiddle(void) +{ + register struct type *tp; + register struct sdef *sd; + register struct e_stack *p = p_stack; + + if (gen_error) { + if (p) return p->s_tpp; + return 0; + } +again: + tp = *(p->s_tpp); + switch(tp->tp_fund) { + case ERRONEOUS: + if (! gen_error) gen_error = pack_level; + return p->s_tpp; + case UNION: + sd = p->s_def; + p->bytes_upto_here += + size_of_type(sd->sd_type, "selector"); + return p->s_tpp; + default: + if (p->elem_count == p->nelem && p->s_nested) { + p = p->next; + free_e_stack(p_stack); + p_stack = p; + goto again; + } + p->elem_count++; + if (p->nelem >= 0 && p->elem_count > p->nelem) { + too_many_initialisers(); + return p->s_tpp; + } + if (tp->tp_fund == ARRAY) { + return arr_elem(p->s_tpp, p); + } + return p->s_tpp; + case STRUCT: + sd = gen_align_to_next(p); + if (! sd) { + while (p->bytes_upto_here++ < tp->tp_size) + con_nullbyte(); + if (p->s_nested) { + p = p->next; + free_e_stack(p_stack); + p_stack = p; + goto again; + } + too_many_initialisers(); + return p->s_tpp; + } + if (AHEAD != '{' && aggregate_type(sd->sd_type)) { + return gen_tphead(&(sd->sd_type), 1); + } + return &(sd->sd_type); + } +} + +struct sdef *gen_align_to_next(register struct e_stack *p) +{ + register struct sdef *sd = p->s_def; + + if (! sd) return sd; +#ifndef NOBITFIELD + do { + if (is_anon_idf(sd->sd_idf)) put_bf(sd->sd_type, (arith) 0); +#endif + sd = next_field(sd, p); +#ifndef NOBITFIELD + } while (sd && is_anon_idf(sd->sd_idf)); +#endif + p->s_def = sd; + return sd; +} + +void gen_tpend(void) +{ + register struct e_stack *p = p_stack; + register struct type *tp; + register struct sdef *sd; + int getout = 0; + + while (!getout && p) { + if (!gen_error) { + tp = *(p->s_tpp); + switch(tp->tp_fund) { + case UNION: + sd = p->s_def; + p->bytes_upto_here += + size_of_type(sd->sd_type, "selector"); + while (p->bytes_upto_here++ < tp->tp_size) + con_nullbyte(); + break; + case ARRAY: + if (tp->tp_size == -1) { + *(p->s_tpp) = construct_type(ARRAY, tp->tp_up, + 0, p->elem_count, NO_PROTO); + } + else { + while (p->nelem-- > p->elem_count) { + pad(tp->tp_up); + } + } + break; + case STRUCT: + sd = gen_align_to_next(p); + while (sd) { + pad(sd->sd_type); + if (sd->sd_sdef) + p->bytes_upto_here += zero_bytes(sd); + p->bytes_upto_here += + size_of_type(sd->sd_type, "selector"); + sd = sd->sd_sdef; + } + while (p->bytes_upto_here++ < tp->tp_size) + con_nullbyte(); + break; + } + } + if (! p->s_nested) getout = 1; + p = p->next; + free_e_stack(p_stack); + p_stack = p; + } +} + +/* check_and_pad() is given a simple initialisation expression + where the type can be either a simple or an aggregate type. + In the latter case, only the first member is initialised and + the rest is zeroed. +*/ +void check_and_pad(struct expr **expp, struct type **tpp) +{ + register struct type *tp = *tpp; + + if (tp->tp_fund == ARRAY) { + check_and_pad(expp, &(tp->tp_up)); /* first member */ + if (tp->tp_size == (arith)-1) + /* no size specified upto here: just + set it to the size of one member. + */ + tp = *tpp = construct_type(ARRAY, tp->tp_up, + 0, (arith)1, NO_PROTO); + else { + register int dim = tp->tp_size / tp->tp_up->tp_size; + /* pad remaining members with zeroes */ + while (--dim > 0) + pad(tp->tp_up); + } + } + else + if (tp->tp_fund == STRUCT) { + register struct sdef *sd = tp->tp_sdef; + + check_and_pad(expp, &(sd->sd_type)); + /* next selector is aligned by adding extra zeroes */ + if (sd->sd_sdef) + zero_bytes(sd); + while ( (sd = sd->sd_sdef)!=0) { /* pad remaining selectors */ + pad(sd->sd_type); + if (sd->sd_sdef) + zero_bytes(sd); + } + } + else if (tp->tp_fund == UNION) { + /* only the first selector can be initialized */ + register struct sdef *sd = tp->tp_sdef; + + check_and_pad(expp, &(sd->sd_type)); + } + else /* simple type */ + check_ival(expp, tp); +} + +/* pad() fills an element of type tp with zeroes. + If the element is an aggregate, pad() is called recursively. +*/ +void pad(struct type *tpx) +{ + register struct type *tp = tpx; + register arith sz = tp->tp_size; + + gen_tpcheck(&tpx); + if (gen_error) return; +#ifndef NOBITFIELD + if (tp->tp_fund == FIELD) { + put_bf(tp, (arith)0); + return; + } +#endif /* NOBITFIELD */ + + if (tp->tp_align >= word_align) while (sz >= word_size) { + C_con_cst((arith) 0); + sz -= word_size; + } + while (sz) { + C_con_icon("0", (arith) 1); + sz--; + } +} + +/* check_ival() checks whether the initialisation of an element + of a fundamental type is legal and, if so, performs the initialisation + by directly generating the necessary code. + No further comment is needed to explain the internal structure + of this straightforward function. +*/ +void check_ival(struct expr **expp, register struct type *tp) +{ + /* The philosophy here is that ch3cast puts an explicit + conversion node in front of the expression if the types + are not compatible. In this case, the initialisation + expression is no longer a constant. + */ + register struct expr *expr = *expp; + + switch (tp->tp_fund) { + case CHAR: + case SHORT: + case INT: + case LONG: + case LNGLNG: + case ENUM: + case POINTER: + ch3cast(expp, '=', tp); + expr = *expp; +#ifdef DEBUG + print_expr("init-expr after cast", expr); +#endif /* DEBUG */ + if (!is_ld_cst(expr)) + illegal_init_cst(expr); + else + if (expr->VL_CLASS == Const) + con_int(expr); + else + if (expr->VL_CLASS == Name) { + register struct idf *idf = expr->VL_IDF; + + if (idf->id_def->df_level >= L_LOCAL + && idf->id_def->df_sc != GLOBAL + && idf->id_def->df_sc != EXTERN) { + illegal_init_cst(expr); + } + else /* e.g., int f(); int p = f; */ + if (idf->id_def->df_type->tp_fund == FUNCTION) + C_con_pnam(idf->id_text); + else /* e.g., int a; int *p = &a; */ + C_con_dnam(idf->id_text, (arith)expr->VL_VALUE); + } + else { + assert(expr->VL_CLASS == Label); + C_con_dlb(expr->VL_LBL, (arith)expr->VL_VALUE); + } + break; + case FLOAT: + case DOUBLE: + case LNGDBL: + ch3cast(expp, '=', tp); + expr = *expp; +#ifdef DEBUG + print_expr("init-expr after cast", expr); +#endif /* DEBUG */ + if (expr->ex_class == Float) { + char buf[FLT_STRLEN]; + + flt_flt2str(&(expr->FL_ARITH), buf, FLT_STRLEN); + C_con_fcon(buf, expr->ex_type->tp_size); + } +#ifdef NOTDEF + +Coercion from int to float is now always done compile time. +This, to accept declarations like +double x = -(double)1; +and also to prevent runtime coercions for compile-time constants. + + else + if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) { + /* float f = 1; */ + expr = expr->OP_RIGHT; + if (is_cp_cst(expr)) + C_con_fcon(long2str((long)expr->VL_VALUE, 10), + tp->tp_size); + else + illegal_init_cst(expr); + } +#endif /* NOTDEF */ + else + illegal_init_cst(expr); + break; + +#ifndef NOBITFIELD + case FIELD: + ch3cast(expp, '=', tp->tp_up); + expr = *expp; +#ifdef DEBUG + print_expr("init-expr after cast", expr); +#endif /* DEBUG */ + if (is_cp_cst(expr)) + put_bf(tp, (arith)expr->VL_VALUE); + else + illegal_init_cst(expr); + break; +#endif /* NOBITFIELD */ + + case ERRONEOUS: + if (! gen_error) gen_error = pack_level; + /* fall through */ + case VOID: + break; + default: + crash("check_ival"); + /*NOTREACHED*/ + } +} + +/* ch_array() initialises an array of characters when given + a string constant. + Alignment is taken care of. +*/ +void ch_array(struct type **tpp, /* type tp = array of characters */ + struct expr *ex) +{ + register struct type *tp = *tpp; + register int length = ex->SG_LEN, i; + register char *to, *from, *s; + + assert(ex->ex_class == String); + if (tp->tp_size == (arith)-1) { + /* set the dimension */ + tp = *tpp = construct_type(ARRAY, tp->tp_up, 0, (arith)length, NO_PROTO); + } + else { + arith dim = tp->tp_size / tp->tp_up->tp_size; + +#ifdef LINT + if (length == dim + 1) { + expr_warning(ex, "array is not null-terminated"); + } else +#endif + if (length > dim + 1) { + expr_strict(ex, "too many initializers"); + } + length = dim; + } + /* throw out the characters of the already prepared string */ + s = Malloc((unsigned) (length)); + clear(s, (unsigned)length); + i = length <= ex->SG_LEN ? length : ex->SG_LEN; + to = s; from = ex->SG_VALUE; + while(--i >= 0) { + *to++ = *from++; + } + free(ex->SG_VALUE); + str_cst(s, length, 0); /* a string, but not in rom */ + free(s); +} + +/* As long as some parts of the pipeline cannot handle very long string + constants, string constants are written out in chunks +*/ +void str_cst(register char *str, register int len, int inrom) +{ + int chunksize = ((127 + (int) word_size) / (int) word_size) * (int) word_size; + + while (len > chunksize) { + if (inrom) + C_rom_scon(str, (arith) chunksize); + else C_con_scon(str, (arith) chunksize); + len -= chunksize; + str += chunksize; + } + if (inrom) + C_rom_scon(str, (arith) len); + else C_con_scon(str, (arith) len); +} + +#ifndef NOBITFIELD +/* put_bf() takes care of the initialisation of (bit-)field + selectors of a struct: each time such an initialisation takes place, + put_bf() is called instead of the normal code generating routines. + Put_bf() stores the given integral value into "field" and + "throws" the result of "field" out if the current selector + is the last of this number of fields stored at the same address. +*/ +void put_bf(struct type *tp, arith val) +{ + static long field = (arith)0; + static arith offset = (arith)-1; + register struct field *fd = tp->tp_field; + register struct sdef *sd = fd->fd_sdef; + static struct expr exp; + + assert(sd); + if (offset == (arith)-1) { + /* first bitfield in this field */ + offset = sd->sd_offset; + exp.ex_type = tp->tp_up; + exp.ex_class = Value; + exp.VL_CLASS = Const; + } + if (val != 0) /* insert the value into "field" */ + field |= (val & fd->fd_mask) << fd->fd_shift; + if (sd->sd_sdef == 0 || sd->sd_sdef->sd_offset != offset) { + /* the selector was the last stored at this address */ + exp.VL_VALUE = (writh)field; + con_int(&exp); + field = (arith)0; + offset = (arith)-1; + } +} +#endif /* NOBITFIELD */ + +int zero_bytes(register struct sdef *sd) +{ + /* fills the space between a selector of a struct + and the next selector of that struct with zero-bytes. + */ + register int n = sd->sd_sdef->sd_offset - sd->sd_offset - + size_of_type(sd->sd_type, "struct member"); + int count = n; + + while (n-- > 0) + con_nullbyte(); + return count; +} + +int valid_type(struct type *tp, char *str) +{ + assert(tp!=(struct type *)0); + if (tp->tp_size < 0) { + error("size of %s unknown", str); + return 0; + } + return 1; +} + +void con_int(register struct expr *ex) +{ + register struct type *tp = ex->ex_type; + + assert(is_cp_cst(ex)); + if (tp->tp_unsigned) + C_con_ucon(writh2str(ex->VL_VALUE, 1), tp->tp_size); + else if (tp->tp_size == word_size) + C_con_cst((arith)ex->VL_VALUE); + else + C_con_icon(writh2str(ex->VL_VALUE, 0), tp->tp_size); +} + +void illegal_init_cst(struct expr *ex) +{ + expr_error(ex, "illegal initialization constant"); + gen_error = pack_level; +} + +void too_many_initialisers(void) +{ + error("too many initializers"); + gen_error = pack_level; +} +} diff --git a/lang/cem/cemcom.ansi/program.g b/lang/cem/cemcom.ansi/program.g index 616065da5..ecb5c25d1 100644 --- a/lang/cem/cemcom.ansi/program.g +++ b/lang/cem/cemcom.ansi/program.g @@ -1,227 +1,227 @@ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -/* $Id$ */ -/* PROGRAM PARSER */ - -/* The presence of typedef declarations renders it impossible to - make a context-free grammar of C. Consequently we need - context-sensitive parsing techniques, the simplest one being - a subtle cooperation between the parser and the lexical scanner. - The lexical scanner has to know whether to return IDENTIFIER - or TYPE_IDENTIFIER for a given tag, and it obtains this information - from the definition list, as constructed by the parser. - The present grammar is essentially LL(2), and is processed by - a parser generator which accepts LL(1) with tie breaking rules - in C, of the form %if(cond) and %while(cond). To solve the LL(1) - ambiguities, the lexical scanner does a one symbol look-ahead. - This symbol, however, cannot always be correctly assessed, since - the present symbol may cause a change in the definition list - which causes the identification of the look-ahead symbol to be - invalidated. - The lexical scanner relies on the parser (or its routines) to - detect this situation and then update the look-ahead symbol. - An alternative approach would be to reassess the look-ahead symbol - in the lexical scanner when it is promoted to dot symbol. This - would be more beautiful but less correct, since then for a short - while there would be a discrepancy between the look-ahead symbol - and the definition list; I think it would nevertheless work in - correct programs. - A third solution would be to enter the identifier as soon as it - is found; its storage class is then known, although its full type - isn't. We would have to fill that in afterwards. - - At block exit the situation is even worse. Upon reading the - closing brace, the names declared inside the function are cleared - from the name list. This action may expose a type identifier that - is the same as the identifier in the look-ahead symbol. This - situation certainly invalidates the third solution, and casts - doubts upon the second. -*/ - -%lexical LLlex; -%start C_program, program; -%start If_expr, control_if_expression; - -{ -#include "parameters.h" -#include -#include "arith.h" -#include "LLlex.h" -#include "label.h" -#include "type.h" -#include "declar.h" -#include "decspecs.h" -#include "code.h" -#include "expr.h" -#include "def.h" -#include "idf.h" -#include "declarator.h" -#include "stack.h" -#include "proto.h" -#include "error.h" -#ifdef LINT -#include "l_lint.h" -#endif /* LINT */ - -} - -control_if_expression - { - struct expr *exprX; - } -: - constant_expression(&exprX) - { - } -; - -/* 3.7 */ -program: - [%persistent external_definition]* - { unstack_world(); } -; - -/* A C identifier definition is remarkable in that it formulates - the declaration in a way different from most other languages: - e.g., rather than defining x as a pointer-to-integer, it defines - *x as an integer and lets the compiler deduce that x is actually - pointer-to-integer. This has profound consequences, both for the - structure of an identifier definition and for the compiler. - - A definition starts with a decl_specifiers, which contains things - like - typedef int - which is implicitly repeated for every definition in the list, and - then for each identifier a declarator is given, of the form - *a() - or so. The decl_specifiers is kept in a struct decspecs, to be - used again and again, while the declarator is stored in a struct - declarator, only to be passed to declare_idf together with the - struct decspecs. - - With the introduction of prototypes, extra problems for the scope - administration were introduced as well. We can have, for example, - int x(double x); - and - int x(double x) { ... use(x) ... } - In the first case, the parameter name can be forgotten, whereas in - the second case, the parameter should have a block scope. The - problem lies in the fact that the parameter's type is known before - the type of the function, which causes the def structure to be on - the end of the list. Our solution is as follows: - 1- In case of a declaration, throw the parameter identifier away - before the declaration of the outer x. - 2- In case of a definition, the function begin_proc() changes the - def list for the identifier. This means that declare_idf() - contains an extra test in case we already saw a declaration of - such a function, because this function is called before - begin_proc(). -*/ - -external_definition - { struct decspecs Ds; - struct declarator Dc; - } -: - { Ds = null_decspecs; - Dc = null_declarator; - } - [ %if (DOT != IDENTIFIER || AHEAD == IDENTIFIER) - decl_specifiers(&Ds) - | - {do_decspecs(&Ds);} - ] - [ - declarator(&Dc) - { - declare_idf(&Ds, &Dc, level); -#ifdef LINT - lint_ext_def(Dc.dc_idf, Ds.ds_sc); -#endif /* LINT */ - } - [ - function(&Ds, &Dc) - | - { if (! Ds.ds_sc_given && ! Ds.ds_typequal && - Ds.ds_notypegiven) { - strict("declaration specifiers missing"); - } - } - non_function(&Ds, &Dc) - ] - | - { if (! Ds.ds_sc_given && ! Ds.ds_typequal && - Ds.ds_notypegiven) { - strict("declaration missing"); - } - } - ';' - ] - {remove_declarator(&Dc); flush_strings(); } -; - -non_function(register struct decspecs *ds; register struct declarator *dc;) -: - { reject_params(dc); - } - [ - initializer(dc->dc_idf, ds->ds_sc) - | - { code_declaration(dc->dc_idf, (struct expr *) 0, level, ds->ds_sc); } - ] - { -#ifdef LINT - lint_non_function_decl(ds, dc); -#endif /* LINT */ - } - [ - ',' - init_declarator(ds) - ]* - ';' -; - -/* 3.7.1 */ -function(struct decspecs *ds; struct declarator *dc;) - { - arith fbytes; - register struct idf *idf = dc->dc_idf; - } -: - { -#ifdef LINT - lint_start_function(); -#endif /* LINT */ - idf_initialized(idf); - stack_level(); /* L_FORMAL1 declarations */ - declare_params(dc); - begin_proc(ds, idf); /* sets global function info */ - stack_level(); /* L_FORMAL2 declarations */ - declare_protos(dc); - } - declaration* - { - check_formals(idf, dc); /* check style-mixtures */ - declare_formals(idf, &fbytes); -#ifdef LINT - lint_formals(); -#endif /* LINT */ - } - compound_statement - { - end_proc(fbytes); -#ifdef LINT - lint_implicit_return(); -#endif /* LINT */ - unstack_level(); /* L_FORMAL2 declarations */ -#ifdef LINT - lint_end_formals(); -#endif /* LINT */ - unstack_level(); /* L_FORMAL1 declarations */ -#ifdef LINT - lint_end_function(); -#endif /* LINT */ - } -; +/* + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ +/* $Id$ */ +/* PROGRAM PARSER */ + +/* The presence of typedef declarations renders it impossible to + make a context-free grammar of C. Consequently we need + context-sensitive parsing techniques, the simplest one being + a subtle cooperation between the parser and the lexical scanner. + The lexical scanner has to know whether to return IDENTIFIER + or TYPE_IDENTIFIER for a given tag, and it obtains this information + from the definition list, as constructed by the parser. + The present grammar is essentially LL(2), and is processed by + a parser generator which accepts LL(1) with tie breaking rules + in C, of the form %if(cond) and %while(cond). To solve the LL(1) + ambiguities, the lexical scanner does a one symbol look-ahead. + This symbol, however, cannot always be correctly assessed, since + the present symbol may cause a change in the definition list + which causes the identification of the look-ahead symbol to be + invalidated. + The lexical scanner relies on the parser (or its routines) to + detect this situation and then update the look-ahead symbol. + An alternative approach would be to reassess the look-ahead symbol + in the lexical scanner when it is promoted to dot symbol. This + would be more beautiful but less correct, since then for a short + while there would be a discrepancy between the look-ahead symbol + and the definition list; I think it would nevertheless work in + correct programs. + A third solution would be to enter the identifier as soon as it + is found; its storage class is then known, although its full type + isn't. We would have to fill that in afterwards. + + At block exit the situation is even worse. Upon reading the + closing brace, the names declared inside the function are cleared + from the name list. This action may expose a type identifier that + is the same as the identifier in the look-ahead symbol. This + situation certainly invalidates the third solution, and casts + doubts upon the second. +*/ + +%lexical LLlex; +%start C_program, program; +%start If_expr, control_if_expression; + +{ +#include "parameters.h" +#include +#include "arith.h" +#include "LLlex.h" +#include "label.h" +#include "type.h" +#include "declar.h" +#include "decspecs.h" +#include "code.h" +#include "expr.h" +#include "def.h" +#include "idf.h" +#include "declarator.h" +#include "stack.h" +#include "proto.h" +#include "error.h" +#ifdef LINT +#include "l_lint.h" +#endif /* LINT */ + +} + +control_if_expression + { + struct expr *exprX; + } +: + constant_expression(&exprX) + { + } +; + +/* 3.7 */ +program: + [%persistent external_definition]* + { unstack_world(); } +; + +/* A C identifier definition is remarkable in that it formulates + the declaration in a way different from most other languages: + e.g., rather than defining x as a pointer-to-integer, it defines + *x as an integer and lets the compiler deduce that x is actually + pointer-to-integer. This has profound consequences, both for the + structure of an identifier definition and for the compiler. + + A definition starts with a decl_specifiers, which contains things + like + typedef int + which is implicitly repeated for every definition in the list, and + then for each identifier a declarator is given, of the form + *a() + or so. The decl_specifiers is kept in a struct decspecs, to be + used again and again, while the declarator is stored in a struct + declarator, only to be passed to declare_idf together with the + struct decspecs. + + With the introduction of prototypes, extra problems for the scope + administration were introduced as well. We can have, for example, + int x(double x); + and + int x(double x) { ... use(x) ... } + In the first case, the parameter name can be forgotten, whereas in + the second case, the parameter should have a block scope. The + problem lies in the fact that the parameter's type is known before + the type of the function, which causes the def structure to be on + the end of the list. Our solution is as follows: + 1- In case of a declaration, throw the parameter identifier away + before the declaration of the outer x. + 2- In case of a definition, the function begin_proc() changes the + def list for the identifier. This means that declare_idf() + contains an extra test in case we already saw a declaration of + such a function, because this function is called before + begin_proc(). +*/ + +external_definition + { struct decspecs Ds; + struct declarator Dc; + } +: + { Ds = null_decspecs; + Dc = null_declarator; + } + [ %if (DOT != IDENTIFIER || AHEAD == IDENTIFIER) + decl_specifiers(&Ds) + | + {do_decspecs(&Ds);} + ] + [ + declarator(&Dc) + { + declare_idf(&Ds, &Dc, level); +#ifdef LINT + lint_ext_def(Dc.dc_idf, Ds.ds_sc); +#endif /* LINT */ + } + [ + function(&Ds, &Dc) + | + { if (! Ds.ds_sc_given && ! Ds.ds_typequal && + Ds.ds_notypegiven) { + strict("declaration specifiers missing"); + } + } + non_function(&Ds, &Dc) + ] + | + { if (! Ds.ds_sc_given && ! Ds.ds_typequal && + Ds.ds_notypegiven) { + strict("declaration missing"); + } + } + ';' + ] + {remove_declarator(&Dc); flush_strings(); } +; + +non_function(register struct decspecs *ds; register struct declarator *dc;) +: + { reject_params(dc); + } + [ + initializer(dc->dc_idf, ds->ds_sc) + | + { code_declaration(dc->dc_idf, (struct expr *) 0, level, ds->ds_sc); } + ] + { +#ifdef LINT + lint_non_function_decl(ds, dc); +#endif /* LINT */ + } + [ + ',' + init_declarator(ds) + ]* + ';' +; + +/* 3.7.1 */ +function(struct decspecs *ds; struct declarator *dc;) + { + arith fbytes; + register struct idf *idf = dc->dc_idf; + } +: + { +#ifdef LINT + lint_start_function(); +#endif /* LINT */ + idf_initialized(idf); + stack_level(); /* L_FORMAL1 declarations */ + declare_params(dc); + begin_proc(ds, idf); /* sets global function info */ + stack_level(); /* L_FORMAL2 declarations */ + declare_protos(dc); + } + declaration* + { + check_formals(idf, dc); /* check style-mixtures */ + declare_formals(idf, &fbytes); +#ifdef LINT + lint_formals(); +#endif /* LINT */ + } + compound_statement + { + end_proc(fbytes); +#ifdef LINT + lint_implicit_return(); +#endif /* LINT */ + unstack_level(); /* L_FORMAL2 declarations */ +#ifdef LINT + lint_end_formals(); +#endif /* LINT */ + unstack_level(); /* L_FORMAL1 declarations */ +#ifdef LINT + lint_end_function(); +#endif /* LINT */ + } +; diff --git a/lang/cem/cemcom.ansi/statement.g b/lang/cem/cemcom.ansi/statement.g index d58ec4b6a..83c741d61 100644 --- a/lang/cem/cemcom.ansi/statement.g +++ b/lang/cem/cemcom.ansi/statement.g @@ -1,506 +1,506 @@ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -/* $Id$ */ -/* STATEMENT SYNTAX PARSER */ - -{ -#include "parameters.h" -#ifndef LINT -#include -#else -#include "l_em.h" -#include "l_lint.h" -#endif /* LINT */ - -#include -#include "idf.h" -#include "arith.h" -#include "LLlex.h" -#include "type.h" -#include "label.h" -#include "expr.h" -#include "code.h" -#include "stack.h" -#include "def.h" -#include "switch.h" -#ifdef DBSYMTAB -#include -#endif /* DBSYMTAB */ - -extern int level; -extern char options[]; -} - -/* Each statement construction is stacked in order to trace a - * statement to such a construction. Example: a case statement should - * be recognized as a piece of the most enclosing switch statement. - */ - -/* 3.6 */ -statement - { -#ifdef LINT - lint_statement(); -#endif /* LINT */ - } -: -%if (AHEAD != ':') - expression_statement -| - label ':' statement -| - compound_statement -| - if_statement -| - while_statement -| - do_statement -| - for_statement -| - switch_statement -| - case_statement -| - default_statement -| - BREAK - { - code_break(); -#ifdef LINT - lint_break_stmt(); -#endif /* LINT */ - } - ';' -| - CONTINUE - { - code_continue(); -#ifdef LINT - lint_continue_stmt(); -#endif /* LINT */ - } - ';' -| - return_statement -| - jump -| - ';' -; - - -expression_statement - { struct expr *expr; - } -: - expression(&expr) - ';' - { -#ifdef DEBUG - print_expr("expression_statement", expr); -#endif /* DEBUG */ - code_expr(expr, RVAL, FALSE, NO_LABEL, NO_LABEL); - free_expression(expr); - } -; - -/* 3.6.1 (partially) */ -label - { struct idf *idf; } -: - identifier(&idf) - { - /* This allows the following absurd case: - - typedef int grz; - main() { - grz: printf("A labelled statement\n"); - } - */ -#ifdef LINT - lint_label(); -#endif /* LINT */ - define_label(idf); - C_df_ilb((label)idf->id_label->df_address); - } -; - -/* 3.6.4.1 */ -if_statement - { - struct expr *expr; - label l_true = text_label(); - label l_false = text_label(); - label l_end = text_label(); - } -: - IF - '(' - expression(&expr) - { - opnd2test(&expr, IF); - if (is_cp_cst(expr)) { - /* The comparison has been optimized - to a 0 or 1. - */ - if (expr->VL_VALUE == 0) { - C_bra(l_false); - } - /* else fall through */ -#ifdef LINT - start_if_part(1); -#endif /* LINT */ - } - else { - code_expr(expr, RVAL, TRUE, l_true, l_false); - C_df_ilb(l_true); -#ifdef LINT - start_if_part(0); -#endif /* LINT */ - } - free_expression(expr); - } - ')' - statement - [%prefer - ELSE - { -#ifdef LINT - start_else_part(); -#endif /* LINT */ - C_bra(l_end); - C_df_ilb(l_false); - } - statement - { C_df_ilb(l_end); -#ifdef LINT - end_if_else_stmt(); -#endif /* LINT */ - } - | - empty - { C_df_ilb(l_false); -#ifdef LINT - end_if_stmt(); -#endif /* LINT */ - } - ] -; - -/* 3.6.5.3 */ -while_statement - { - struct expr *expr; - label l_break = text_label(); - label l_continue = text_label(); - label l_body = text_label(); - } -: - WHILE - { - stack_stmt(l_break, l_continue); - C_df_ilb(l_continue); - } - '(' - expression(&expr) - { - opnd2test(&expr, WHILE); - if (is_cp_cst(expr)) { - if (expr->VL_VALUE == 0) { - C_bra(l_break); - } - } - else { - code_expr(expr, RVAL, TRUE, l_body, l_break); - C_df_ilb(l_body); - } -#ifdef LINT - start_while_stmt(expr); -#endif /* LINT */ - } - ')' - statement - { - C_bra(l_continue); - C_df_ilb(l_break); - unstack_stmt(); - free_expression(expr); -#ifdef LINT - end_loop_body(); - end_loop_stmt(); -#endif /* LINT */ - } -; - -/* 3.6.5.2 */ -do_statement - { struct expr *expr; - label l_break = text_label(); - label l_continue = text_label(); - label l_body = text_label(); - } -: - DO - { C_df_ilb(l_body); - stack_stmt(l_break, l_continue); -#ifdef LINT - start_do_stmt(); -#endif /* LINT */ - } - statement - WHILE - '(' - { -#ifdef LINT - end_loop_body(); -#endif /* LINT */ - C_df_ilb(l_continue); - } - expression(&expr) - { - opnd2test(&expr, WHILE); - if (is_cp_cst(expr)) { - if (expr->VL_VALUE == 1) { - C_bra(l_body); - } -#ifdef LINT - end_do_stmt(1, expr->VL_VALUE != 0); -#endif /* LINT */ - } - else { - code_expr(expr, RVAL, TRUE, l_body, l_break); -#ifdef LINT - end_do_stmt(0, 0); -#endif /* LINT */ - } - C_df_ilb(l_break); - } - ')' - ';' - { - unstack_stmt(); - free_expression(expr); - } -; - -/* 3.6.5.3 */ -for_statement - { struct expr *e_init = 0, *e_test = 0, *e_incr = 0; - label l_break = text_label(); - label l_continue = text_label(); - label l_body = text_label(); - label l_test = text_label(); - } -: - FOR - { stack_stmt(l_break, l_continue); - } - '(' - [ - expression(&e_init) - { code_expr(e_init, RVAL, FALSE, NO_LABEL, NO_LABEL); - } - ]? - ';' - { C_df_ilb(l_test); - } - [ - expression(&e_test) - { - opnd2test(&e_test, FOR); - if (is_cp_cst(e_test)) { - if (e_test->VL_VALUE == 0) { - C_bra(l_break); - } - } - else { - code_expr(e_test, RVAL, TRUE, l_body, l_break); - C_df_ilb(l_body); - } - } - ]? - ';' - expression(&e_incr)? - ')' - { -#ifdef LINT - start_for_stmt(e_test); -#endif /* LINT */ - } - statement - { -#ifdef LINT - end_loop_body(); -#endif /* LINT */ - C_df_ilb(l_continue); - if (e_incr) - code_expr(e_incr, RVAL, FALSE, - NO_LABEL, NO_LABEL); - C_bra(l_test); - C_df_ilb(l_break); - unstack_stmt(); - free_expression(e_init); - free_expression(e_test); - free_expression(e_incr); -#ifdef LINT - end_loop_stmt(); -#endif /* LINT */ - } -; - -/* 3.6.4.2 */ -switch_statement - { - struct expr *expr; - } -: - SWITCH - '(' - expression(&expr) - { - code_startswitch(&expr); -#ifdef LINT - start_switch_part(is_cp_cst(expr)); -#endif /* LINT */ - } - ')' - statement - { -#ifdef LINT - end_switch_stmt(); -#endif /* LINT */ - code_endswitch(); - free_expression(expr); - } -; - -/* 3.6.1 (partially) */ -case_statement - { - struct expr *expr; - } -: - CASE - constant_expression(&expr) - { -#ifdef LINT - lint_case_stmt(0); -#endif /* LINT */ - code_case(expr); - free_expression(expr); - } - ':' - statement -; - -/* 3.6.1 (partially) */ -default_statement -: - DEFAULT - { -#ifdef LINT - lint_case_stmt(1); -#endif /* LINT */ - code_default(); - } - ':' - statement -; - -/* 3.6.6.4 */ -return_statement - { struct expr *expr = 0; - } -: - RETURN - [ - expression(&expr) - { -#ifdef LINT - lint_ret_conv(expr); -#endif /* LINT */ - - do_return_expr(expr); - free_expression(expr); -#ifdef LINT - lint_return_stmt(VALRETURNED); -#endif /* LINT */ - } - | - empty - { - do_return(); -#ifdef LINT - lint_return_stmt(NOVALRETURNED); -#endif /* LINT */ - } - ] - ';' -; - -/* 3.6.6.1 (partially) */ -jump - { struct idf *idf; - } -: - GOTO - identifier(&idf) - ';' - { - apply_label(idf); - C_bra((label)idf->id_label->df_address); -#ifdef LINT - lint_jump_stmt(idf); -#endif /* LINT */ - } -; - -/* 3.6.2 */ -compound_statement - { -#ifdef DBSYMTAB - static int brc_level = 1; - int decl_seen = brc_level == 1; -#endif /* DBSYMTAB */ - } -: - '{' - { - stack_level(); - } - [%while ((DOT != IDENTIFIER && AHEAD != ':') || - (DOT == IDENTIFIER && AHEAD == IDENTIFIER)) - /* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */ - declaration - { -#ifdef DBSYMTAB - decl_seen++; -#endif /* DBSYMTAB */ - } - ]* - { -#ifdef DBSYMTAB - ++brc_level; - if (options['g'] && decl_seen) { - C_ms_std((char *) 0, N_LBRAC, brc_level); - } -#endif /* DBSYMTAB */ - } - [%persistent - statement - ]* - '}' - { - unstack_level(); -#ifdef DBSYMTAB - if (options['g'] && decl_seen) { - C_ms_std((char *) 0, N_RBRAC, brc_level); - } - brc_level--; -#endif /* DBSYMTAB */ - } -; +/* + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ +/* $Id$ */ +/* STATEMENT SYNTAX PARSER */ + +{ +#include "parameters.h" +#ifndef LINT +#include +#else +#include "l_em.h" +#include "l_lint.h" +#endif /* LINT */ + +#include +#include "idf.h" +#include "arith.h" +#include "LLlex.h" +#include "type.h" +#include "label.h" +#include "expr.h" +#include "code.h" +#include "stack.h" +#include "def.h" +#include "switch.h" +#ifdef DBSYMTAB +#include +#endif /* DBSYMTAB */ + +extern int level; +extern char options[]; +} + +/* Each statement construction is stacked in order to trace a + * statement to such a construction. Example: a case statement should + * be recognized as a piece of the most enclosing switch statement. + */ + +/* 3.6 */ +statement + { +#ifdef LINT + lint_statement(); +#endif /* LINT */ + } +: +%if (AHEAD != ':') + expression_statement +| + label ':' statement +| + compound_statement +| + if_statement +| + while_statement +| + do_statement +| + for_statement +| + switch_statement +| + case_statement +| + default_statement +| + BREAK + { + code_break(); +#ifdef LINT + lint_break_stmt(); +#endif /* LINT */ + } + ';' +| + CONTINUE + { + code_continue(); +#ifdef LINT + lint_continue_stmt(); +#endif /* LINT */ + } + ';' +| + return_statement +| + jump +| + ';' +; + + +expression_statement + { struct expr *expr; + } +: + expression(&expr) + ';' + { +#ifdef DEBUG + print_expr("expression_statement", expr); +#endif /* DEBUG */ + code_expr(expr, RVAL, FALSE, NO_LABEL, NO_LABEL); + free_expression(expr); + } +; + +/* 3.6.1 (partially) */ +label + { struct idf *idf; } +: + identifier(&idf) + { + /* This allows the following absurd case: + + typedef int grz; + main() { + grz: printf("A labelled statement\n"); + } + */ +#ifdef LINT + lint_label(); +#endif /* LINT */ + define_label(idf); + C_df_ilb((label)idf->id_label->df_address); + } +; + +/* 3.6.4.1 */ +if_statement + { + struct expr *expr; + label l_true = text_label(); + label l_false = text_label(); + label l_end = text_label(); + } +: + IF + '(' + expression(&expr) + { + opnd2test(&expr, IF); + if (is_cp_cst(expr)) { + /* The comparison has been optimized + to a 0 or 1. + */ + if (expr->VL_VALUE == 0) { + C_bra(l_false); + } + /* else fall through */ +#ifdef LINT + start_if_part(1); +#endif /* LINT */ + } + else { + code_expr(expr, RVAL, TRUE, l_true, l_false); + C_df_ilb(l_true); +#ifdef LINT + start_if_part(0); +#endif /* LINT */ + } + free_expression(expr); + } + ')' + statement + [%prefer + ELSE + { +#ifdef LINT + start_else_part(); +#endif /* LINT */ + C_bra(l_end); + C_df_ilb(l_false); + } + statement + { C_df_ilb(l_end); +#ifdef LINT + end_if_else_stmt(); +#endif /* LINT */ + } + | + empty + { C_df_ilb(l_false); +#ifdef LINT + end_if_stmt(); +#endif /* LINT */ + } + ] +; + +/* 3.6.5.3 */ +while_statement + { + struct expr *expr; + label l_break = text_label(); + label l_continue = text_label(); + label l_body = text_label(); + } +: + WHILE + { + stack_stmt(l_break, l_continue); + C_df_ilb(l_continue); + } + '(' + expression(&expr) + { + opnd2test(&expr, WHILE); + if (is_cp_cst(expr)) { + if (expr->VL_VALUE == 0) { + C_bra(l_break); + } + } + else { + code_expr(expr, RVAL, TRUE, l_body, l_break); + C_df_ilb(l_body); + } +#ifdef LINT + start_while_stmt(expr); +#endif /* LINT */ + } + ')' + statement + { + C_bra(l_continue); + C_df_ilb(l_break); + unstack_stmt(); + free_expression(expr); +#ifdef LINT + end_loop_body(); + end_loop_stmt(); +#endif /* LINT */ + } +; + +/* 3.6.5.2 */ +do_statement + { struct expr *expr; + label l_break = text_label(); + label l_continue = text_label(); + label l_body = text_label(); + } +: + DO + { C_df_ilb(l_body); + stack_stmt(l_break, l_continue); +#ifdef LINT + start_do_stmt(); +#endif /* LINT */ + } + statement + WHILE + '(' + { +#ifdef LINT + end_loop_body(); +#endif /* LINT */ + C_df_ilb(l_continue); + } + expression(&expr) + { + opnd2test(&expr, WHILE); + if (is_cp_cst(expr)) { + if (expr->VL_VALUE == 1) { + C_bra(l_body); + } +#ifdef LINT + end_do_stmt(1, expr->VL_VALUE != 0); +#endif /* LINT */ + } + else { + code_expr(expr, RVAL, TRUE, l_body, l_break); +#ifdef LINT + end_do_stmt(0, 0); +#endif /* LINT */ + } + C_df_ilb(l_break); + } + ')' + ';' + { + unstack_stmt(); + free_expression(expr); + } +; + +/* 3.6.5.3 */ +for_statement + { struct expr *e_init = 0, *e_test = 0, *e_incr = 0; + label l_break = text_label(); + label l_continue = text_label(); + label l_body = text_label(); + label l_test = text_label(); + } +: + FOR + { stack_stmt(l_break, l_continue); + } + '(' + [ + expression(&e_init) + { code_expr(e_init, RVAL, FALSE, NO_LABEL, NO_LABEL); + } + ]? + ';' + { C_df_ilb(l_test); + } + [ + expression(&e_test) + { + opnd2test(&e_test, FOR); + if (is_cp_cst(e_test)) { + if (e_test->VL_VALUE == 0) { + C_bra(l_break); + } + } + else { + code_expr(e_test, RVAL, TRUE, l_body, l_break); + C_df_ilb(l_body); + } + } + ]? + ';' + expression(&e_incr)? + ')' + { +#ifdef LINT + start_for_stmt(e_test); +#endif /* LINT */ + } + statement + { +#ifdef LINT + end_loop_body(); +#endif /* LINT */ + C_df_ilb(l_continue); + if (e_incr) + code_expr(e_incr, RVAL, FALSE, + NO_LABEL, NO_LABEL); + C_bra(l_test); + C_df_ilb(l_break); + unstack_stmt(); + free_expression(e_init); + free_expression(e_test); + free_expression(e_incr); +#ifdef LINT + end_loop_stmt(); +#endif /* LINT */ + } +; + +/* 3.6.4.2 */ +switch_statement + { + struct expr *expr; + } +: + SWITCH + '(' + expression(&expr) + { + code_startswitch(&expr); +#ifdef LINT + start_switch_part(is_cp_cst(expr)); +#endif /* LINT */ + } + ')' + statement + { +#ifdef LINT + end_switch_stmt(); +#endif /* LINT */ + code_endswitch(); + free_expression(expr); + } +; + +/* 3.6.1 (partially) */ +case_statement + { + struct expr *expr; + } +: + CASE + constant_expression(&expr) + { +#ifdef LINT + lint_case_stmt(0); +#endif /* LINT */ + code_case(expr); + free_expression(expr); + } + ':' + statement +; + +/* 3.6.1 (partially) */ +default_statement +: + DEFAULT + { +#ifdef LINT + lint_case_stmt(1); +#endif /* LINT */ + code_default(); + } + ':' + statement +; + +/* 3.6.6.4 */ +return_statement + { struct expr *expr = 0; + } +: + RETURN + [ + expression(&expr) + { +#ifdef LINT + lint_ret_conv(expr); +#endif /* LINT */ + + do_return_expr(expr); + free_expression(expr); +#ifdef LINT + lint_return_stmt(VALRETURNED); +#endif /* LINT */ + } + | + empty + { + do_return(); +#ifdef LINT + lint_return_stmt(NOVALRETURNED); +#endif /* LINT */ + } + ] + ';' +; + +/* 3.6.6.1 (partially) */ +jump + { struct idf *idf; + } +: + GOTO + identifier(&idf) + ';' + { + apply_label(idf); + C_bra((label)idf->id_label->df_address); +#ifdef LINT + lint_jump_stmt(idf); +#endif /* LINT */ + } +; + +/* 3.6.2 */ +compound_statement + { +#ifdef DBSYMTAB + static int brc_level = 1; + int decl_seen = brc_level == 1; +#endif /* DBSYMTAB */ + } +: + '{' + { + stack_level(); + } + [%while ((DOT != IDENTIFIER && AHEAD != ':') || + (DOT == IDENTIFIER && AHEAD == IDENTIFIER)) + /* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */ + declaration + { +#ifdef DBSYMTAB + decl_seen++; +#endif /* DBSYMTAB */ + } + ]* + { +#ifdef DBSYMTAB + ++brc_level; + if (options['g'] && decl_seen) { + C_ms_std((char *) 0, N_LBRAC, brc_level); + } +#endif /* DBSYMTAB */ + } + [%persistent + statement + ]* + '}' + { + unstack_level(); +#ifdef DBSYMTAB + if (options['g'] && decl_seen) { + C_ms_std((char *) 0, N_RBRAC, brc_level); + } + brc_level--; +#endif /* DBSYMTAB */ + } +; diff --git a/lang/cem/cemcom.ansi/tokcasee.in b/lang/cem/cemcom.ansi/tokcasee.in index 5df07e7c9..df8f6c608 100644 --- a/lang/cem/cemcom.ansi/tokcasee.in +++ b/lang/cem/cemcom.ansi/tokcasee.in @@ -1,16 +1,16 @@ - default: - if (tok <= 0) return "end of file"; - if (tok < 040 || tok >= 0177) { - return "bad token"; - } - /* fall through */ - case '\n': - case '\f': - case '\v': - case '\r': - case '\t': - index = (index+2) & (SIZBUF-1); - buf[index] = tok; - return &buf[index]; - } + default: + if (tok <= 0) return "end of file"; + if (tok < 040 || tok >= 0177) { + return "bad token"; + } + /* fall through */ + case '\n': + case '\f': + case '\v': + case '\r': + case '\t': + index = (index+2) & (SIZBUF-1); + buf[index] = tok; + return &buf[index]; + } } \ No newline at end of file diff --git a/lang/cem/cemcom.ansi/tokcaseh.in b/lang/cem/cemcom.ansi/tokcaseh.in index 63b1932cb..3b3acba22 100644 --- a/lang/cem/cemcom.ansi/tokcaseh.in +++ b/lang/cem/cemcom.ansi/tokcaseh.in @@ -1,12 +1,12 @@ -/* Generated by make.tokcase */ -/* $Id$ */ -#include "Lpars.h" - -char *symbol2str(int tok) -{ -#define SIZBUF 8 - /* allow for a few invocations in f.i. an argument list */ - static char buf[SIZBUF]; - static int index; - - switch (tok) { +/* Generated by make.tokcase */ +/* $Id$ */ +#include "Lpars.h" + +char *symbol2str(int tok) +{ +#define SIZBUF 8 + /* allow for a few invocations in f.i. an argument list */ + static char buf[SIZBUF]; + static int index; + + switch (tok) { diff --git a/modules/src/alloc/Amake.srclist b/modules/src/alloc/Amake.srclist index 829f2183b..377a0a5ba 100644 --- a/modules/src/alloc/Amake.srclist +++ b/modules/src/alloc/Amake.srclist @@ -1,13 +1,13 @@ -L_ACK_MODULES_ALLOC = { - $PWD/Malloc.c, - $PWD/Salloc.c, - $PWD/Srealloc.c, - $PWD/Realloc.c, - $PWD/botch.c, - $PWD/clear.c, - $PWD/st_alloc.c, - $PWD/std_alloc.c, - $PWD/No_Mem.c, - $PWD/alloc.h -}; - +L_ACK_MODULES_ALLOC = { + $PWD/Malloc.c, + $PWD/Salloc.c, + $PWD/Srealloc.c, + $PWD/Realloc.c, + $PWD/botch.c, + $PWD/clear.c, + $PWD/st_alloc.c, + $PWD/std_alloc.c, + $PWD/No_Mem.c, + $PWD/alloc.h +}; + diff --git a/modules/src/alloc/alloc.3 b/modules/src/alloc/alloc.3 index 5db5745d8..8cc7c32df 100644 --- a/modules/src/alloc/alloc.3 +++ b/modules/src/alloc/alloc.3 @@ -1,80 +1,80 @@ -.TH ALLOC 3 "$Revision$" -.ad -.SH NAME -Malloc, Salloc, Realloc, Srealloc, st_alloc, st_free\ \-\ low level memory allocation routines -.SH SYNOPSIS -.B #include -.PP -.B char *Malloc(unsigned int size) -.PP -.B char *Salloc(char *str, unsigned int size) -.PP -.B char *Realloc(char *buf, unsigned int size) -.PP -.B char *Srealloc(char *str, unsigned int size) -.PP -.B char *st_alloc(char **phead, unsigned int size, int count) -.PP -.B st_free(char *ptr, char **phead, unsigned int size) -.PP -.B void clear(char *ptr, unsigned int size) -.PP -.void No_Mem() -.PP -.SH DESCRIPTION -This set of routines provides a checking memory allocation mechanism. -.PP -\fIMalloc\fR returns a pointer to a block of at least \fIsize\fR -bytes, beginning on a boundary suitable for any data type. -.PP -\fISalloc\fR returns a pointer to a block of at least \fIsize\fR -bytes, initialized with the null-terminated string \fIstr\fR. -.PP -\fIRealloc\fR changes the size of -the block at \fIbuf\fR to \fIsize\fR bytes, and returns a pointer to the -(possibly moved) block. If \fIbuf\fP is a null pointer, \fIRealloc\fP -behaves as \fIMalloc\fP. -.PP -\fISrealloc\fR reallocates -the string at \fIstr\fR to \fIsize\fR bytes. -It actually does the same as \fIRealloc\fP, and exists only for -backwards compatibility. -.PP -All these routines use \fImalloc\fR and \fIrealloc\fR. -The routine \fIfree\fR can be used on pointers returned by these routines. -.PP -\fISt_alloc\fR and \fIst_free\fR provide a mechanism for maintaining free lists -of structures. -\fISt_alloc\fR takes three parameters: \fIphead\fR is a pointer to a field -containing the head of the free list, \fIsize\fR contains the size of the -structures, and \fIcount\fR indicates how many new structures must be allocated -in case the free list is exhausted. -It returns a pointer to a zero-initialized structure. -\fISt_free\fR also takes three parameters: \fIptr\fR is a pointer to -the structure to be freed, \fIphead\fR is again a pointer to a field -containing the head of the free list, and \fIsize\fR again contains the size -of the structures. -These last two routines are best used in a macro. -.PP -\fIclear\fR clears \fIsize\fR bytes, starting at \fIptr\fR. -.SH FILES -.nf -~em/modules/h/alloc.h -~em/modules/lib/liballoc.a -.fi -.SH "SEE ALSO" -malloc(3) -.SH DIAGNOSTICS -\fIMalloc\fR, \fISalloc\fR, \fIRealloc\fP, \fISrealloc\fR, and \fIst_alloc\fR -call a routine \fINo_Mem\fR if there is no memory available. This routine -is not supposed to return. A default one, that -gives an error message and stops execution, is provided. -.SH BUGS -The -.I st_alloc -mechanism only works for structures that are large enough to contain one -pointer. -Also, -.I st_free -actually is a macro, and references its arguments more than once, so they -better not have side-effects. +.TH ALLOC 3 "$Revision$" +.ad +.SH NAME +Malloc, Salloc, Realloc, Srealloc, st_alloc, st_free\ \-\ low level memory allocation routines +.SH SYNOPSIS +.B #include +.PP +.B char *Malloc(unsigned int size) +.PP +.B char *Salloc(char *str, unsigned int size) +.PP +.B char *Realloc(char *buf, unsigned int size) +.PP +.B char *Srealloc(char *str, unsigned int size) +.PP +.B char *st_alloc(char **phead, unsigned int size, int count) +.PP +.B st_free(char *ptr, char **phead, unsigned int size) +.PP +.B void clear(char *ptr, unsigned int size) +.PP +.void No_Mem() +.PP +.SH DESCRIPTION +This set of routines provides a checking memory allocation mechanism. +.PP +\fIMalloc\fR returns a pointer to a block of at least \fIsize\fR +bytes, beginning on a boundary suitable for any data type. +.PP +\fISalloc\fR returns a pointer to a block of at least \fIsize\fR +bytes, initialized with the null-terminated string \fIstr\fR. +.PP +\fIRealloc\fR changes the size of +the block at \fIbuf\fR to \fIsize\fR bytes, and returns a pointer to the +(possibly moved) block. If \fIbuf\fP is a null pointer, \fIRealloc\fP +behaves as \fIMalloc\fP. +.PP +\fISrealloc\fR reallocates +the string at \fIstr\fR to \fIsize\fR bytes. +It actually does the same as \fIRealloc\fP, and exists only for +backwards compatibility. +.PP +All these routines use \fImalloc\fR and \fIrealloc\fR. +The routine \fIfree\fR can be used on pointers returned by these routines. +.PP +\fISt_alloc\fR and \fIst_free\fR provide a mechanism for maintaining free lists +of structures. +\fISt_alloc\fR takes three parameters: \fIphead\fR is a pointer to a field +containing the head of the free list, \fIsize\fR contains the size of the +structures, and \fIcount\fR indicates how many new structures must be allocated +in case the free list is exhausted. +It returns a pointer to a zero-initialized structure. +\fISt_free\fR also takes three parameters: \fIptr\fR is a pointer to +the structure to be freed, \fIphead\fR is again a pointer to a field +containing the head of the free list, and \fIsize\fR again contains the size +of the structures. +These last two routines are best used in a macro. +.PP +\fIclear\fR clears \fIsize\fR bytes, starting at \fIptr\fR. +.SH FILES +.nf +~em/modules/h/alloc.h +~em/modules/lib/liballoc.a +.fi +.SH "SEE ALSO" +malloc(3) +.SH DIAGNOSTICS +\fIMalloc\fR, \fISalloc\fR, \fIRealloc\fP, \fISrealloc\fR, and \fIst_alloc\fR +call a routine \fINo_Mem\fR if there is no memory available. This routine +is not supposed to return. A default one, that +gives an error message and stops execution, is provided. +.SH BUGS +The +.I st_alloc +mechanism only works for structures that are large enough to contain one +pointer. +Also, +.I st_free +actually is a macro, and references its arguments more than once, so they +better not have side-effects. diff --git a/plat/cpm/emu/bdos.s b/plat/cpm/emu/bdos.s index a2a59487f..0450fb8b6 100644 --- a/plat/cpm/emu/bdos.s +++ b/plat/cpm/emu/bdos.s @@ -1,116 +1,116 @@ -# -.sect .text -.sect .rom -.sect .data -.sect .bss - -.sect .text - -bdos: ! BDOS entry point - out 0xff - ora a - ret - -COLDSTART: ! system startup entry point --- this needs to be four bytes after FBASE. - jmp boot ! 0: Cold start routine -bios: - jmp wboot ! 1: Warm boot - reload command processor - jmp const ! 2: Console status - jmp conin ! 3: Console input - jmp conout ! 4: Console output - jmp list ! 5: Printer output - jmp punch ! 6: Paper tape punch output - jmp reader ! 7: Paper tape reader input - jmp home ! 8: Move disc head to track 0 - jmp seldsk ! 9: Select disc drive - jmp settrk !10: Set track number - jmp setsec !11: Set sector number - jmp setdma !12: Set DMA address - jmp read !13: Read a sector - jmp write !14: Write a sector - -boot: - xra a - sta 3 ! iobyte - sta 4 ! drive - ! falls through -wboot: - mvi a, 0xc3 ! jmp - sta 0 - sta 5 - - lxi h, bios - shld 1 - - lxi h, bdos - shld 6 - - lda 4 ! get the current drive/user - mov c, a - out 1 - -const: - out 2 - ora a - ret - -conin: - out 3 - ora a - ret - -conout: - out 4 - ora a - ret - -list: - out 5 - ora a - ret - -punch: - out 6 - ora a - ret - -reader: - out 7 - ora a - ret - -home: - out 8 - ora a - ret - -seldsk: - out 9 - ora a - ret - -settrk: - out 10 - ora a - ret - -setsec: - out 11 - ora a - ret - -setdma: - out 12 - ora a - ret - -read: - out 13 - ora a - ret - -write: - out 14 - ora a - ret - +# +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +bdos: ! BDOS entry point + out 0xff + ora a + ret + +COLDSTART: ! system startup entry point --- this needs to be four bytes after FBASE. + jmp boot ! 0: Cold start routine +bios: + jmp wboot ! 1: Warm boot - reload command processor + jmp const ! 2: Console status + jmp conin ! 3: Console input + jmp conout ! 4: Console output + jmp list ! 5: Printer output + jmp punch ! 6: Paper tape punch output + jmp reader ! 7: Paper tape reader input + jmp home ! 8: Move disc head to track 0 + jmp seldsk ! 9: Select disc drive + jmp settrk !10: Set track number + jmp setsec !11: Set sector number + jmp setdma !12: Set DMA address + jmp read !13: Read a sector + jmp write !14: Write a sector + +boot: + xra a + sta 3 ! iobyte + sta 4 ! drive + ! falls through +wboot: + mvi a, 0xc3 ! jmp + sta 0 + sta 5 + + lxi h, bios + shld 1 + + lxi h, bdos + shld 6 + + lda 4 ! get the current drive/user + mov c, a + out 1 + +const: + out 2 + ora a + ret + +conin: + out 3 + ora a + ret + +conout: + out 4 + ora a + ret + +list: + out 5 + ora a + ret + +punch: + out 6 + ora a + ret + +reader: + out 7 + ora a + ret + +home: + out 8 + ora a + ret + +seldsk: + out 9 + ora a + ret + +settrk: + out 10 + ora a + ret + +setsec: + out 11 + ora a + ret + +setdma: + out 12 + ora a + ret + +read: + out 13 + ora a + ret + +write: + out 14 + ora a + ret + diff --git a/plat/cpm/emu/intel_8080_emulator.c b/plat/cpm/emu/intel_8080_emulator.c index af99ba49a..e88e1245d 100644 --- a/plat/cpm/emu/intel_8080_emulator.c +++ b/plat/cpm/emu/intel_8080_emulator.c @@ -1,874 +1,874 @@ -/* - Intel 8080 emulator in C - Written by Mike Chambers, April 2018 - - Use this code for whatever you want. I don't care. It's officially public domain. - Credit would be appreciated. -*/ - -#include -#include -#include -#include "intel_8080_emulator.h" - -#define ALLOW_UNDEFINED - -#define reg16_PSW (((uint16_t)reg8[A] << 8) | (uint16_t)reg8[FLAGS]) -#define reg16_BC (((uint16_t)reg8[B] << 8) | (uint16_t)reg8[C]) -#define reg16_DE (((uint16_t)reg8[D] << 8) | (uint16_t)reg8[E]) -#define reg16_HL (((uint16_t)reg8[H] << 8) | (uint16_t)reg8[L]) - -uint8_t reg8[9], INTE = 0; -uint16_t reg_SP, reg_PC; - -#define set_S() reg8[FLAGS] |= 0x80 -#define set_Z() reg8[FLAGS] |= 0x40 -#define set_AC() reg8[FLAGS] |= 0x10 -#define set_P() reg8[FLAGS] |= 0x04 -#define set_C() reg8[FLAGS] |= 0x01 -#define clear_S() reg8[FLAGS] &= 0x7F -#define clear_Z() reg8[FLAGS] &= 0xBF -#define clear_AC() reg8[FLAGS] &= 0xEF -#define clear_P() reg8[FLAGS] &= 0xFB -#define clear_C() reg8[FLAGS] &= 0xFE -#define test_S() (reg8[FLAGS] & 0x80) -#define test_Z() (reg8[FLAGS] & 0x40) -#define test_AC() (reg8[FLAGS] & 0x10) -#define test_P() (reg8[FLAGS] & 0x04) -#define test_C() (reg8[FLAGS] & 0x01) - -static const uint8_t parity[0x100] = { - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 -}; - -uint16_t read_RP(uint8_t rp) { - switch (rp) { - case 0x00: - return reg16_BC; - case 0x01: - return reg16_DE; - case 0x02: - return reg16_HL; - case 0x03: - return reg_SP; - } - return 0; -} - -uint16_t read_RP_PUSHPOP(uint8_t rp) { - switch (rp) { - case 0x00: - return reg16_BC; - case 0x01: - return reg16_DE; - case 0x02: - return reg16_HL; - case 0x03: - return (reg16_PSW | 0x02) & 0xFFD7; - } - return 0; -} - -void write_RP(uint8_t rp, uint8_t lb, uint8_t hb) { - switch (rp) { - case 0x00: - reg8[C] = lb; - reg8[B] = hb; - break; - case 0x01: - reg8[E] = lb; - reg8[D] = hb; - break; - case 0x02: - reg8[L] = lb; - reg8[H] = hb; - break; - case 0x03: - reg_SP = (uint16_t)lb | ((uint16_t)hb << 8); - break; - } -} - -void write16_RP(uint8_t rp, uint16_t value) { - switch (rp) { - case 0x00: - reg8[C] = value & 0x00FF; - reg8[B] = value >> 8; - break; - case 0x01: - reg8[E] = value & 0x00FF; - reg8[D] = value >> 8; - break; - case 0x02: - reg8[L] = value & 0x00FF; - reg8[H] = value >> 8; - break; - case 0x03: - reg_SP = value; - break; - } -} - -void write16_RP_PUSHPOP(uint8_t rp, uint16_t value) { - switch (rp) { - case 0x00: - reg8[C] = value & 0x00FF; - reg8[B] = value >> 8; - break; - case 0x01: - reg8[E] = value & 0x00FF; - reg8[D] = value >> 8; - break; - case 0x02: - reg8[L] = value & 0x00FF; - reg8[H] = value >> 8; - break; - case 0x03: - reg8[FLAGS] = ((value & 0x00FF) | 0x02) & 0xD7; - reg8[A] = value >> 8; - break; - } -} - -void calc_SZP(uint8_t value) { - if (value == 0) set_Z(); else clear_Z(); - if (value & 0x80) set_S(); else clear_S(); - if (parity[value]) set_P(); else clear_P(); -} - -void calc_AC(uint8_t val1, uint8_t val2) { - if (((val1 & 0x0F) + (val2 & 0x0F)) > 0x0F) { - set_AC(); - } else { - clear_AC(); - } -} - -void calc_AC_carry(uint8_t val1, uint8_t val2) { - if (((val1 & 0x0F) + (val2 & 0x0F)) >= 0x0F) { - set_AC(); - } else { - clear_AC(); - } -} - -void calc_subAC(int8_t val1, uint8_t val2) { - if ((val2 & 0x0F) <= (val1 & 0x0F)) { - set_AC(); - } else { - clear_AC(); - } -} - -void calc_subAC_borrow(int8_t val1, uint8_t val2) { - if ((val2 & 0x0F) < (val1 & 0x0F)) { - set_AC(); - } else { - clear_AC(); - } -} - -uint8_t test_cond(uint8_t code) { - switch (code) { - case 0: //Z not set - if (!test_Z()) return 1; else return 0; - case 1: //Z set - if (test_Z()) return 1; else return 0; - case 2: //C not set - if (!test_C()) return 1; else return 0; - case 3: //C set - if (test_C()) return 1; else return 0; - case 4: //P not set - if (!test_P()) return 1; else return 0; - case 5: //P set - if (test_P()) return 1; else return 0; - case 6: //S not set - if (!test_S()) return 1; else return 0; - case 7: //S set - if (test_S()) return 1; else return 0; - } - return 0; -} - -void i8080_push(uint16_t value) { - i8080_write(--reg_SP, value >> 8); - i8080_write(--reg_SP, (uint8_t)value); -} - -uint16_t i8080_pop() { - uint16_t temp; - temp = i8080_read(reg_SP++); - temp |= (uint16_t)i8080_read(reg_SP++) << 8; - return temp; -} - -void i8080_interrupt(uint8_t n) { - if (!INTE) return; - i8080_push(reg_PC); - reg_PC = (uint16_t)n << 3; - INTE = 0; -} - -void i8080_jump(uint16_t addr) { - reg_PC = addr; -} - -void i8080_reset() { - reg_PC = reg_SP = 0x0000; - //reg8[FLAGS] = 0x02; -} - -void i8080_write_reg8(reg_t reg, uint8_t value) { - if (reg == M) { - i8080_write(reg16_HL, value); - } else { - reg8[reg] = value; - } -} - -uint8_t i8080_read_reg8(reg_t reg) { - if (reg == M) { - return i8080_read(reg16_HL); - } else { - return reg8[reg]; - } -} - -uint16_t i8080_read_reg16(reg_t reg) { - switch (reg) { - case AF: return reg16_PSW; - case BC: return reg16_BC; - case DE: return reg16_DE; - case HL: return reg16_HL; - case SP: return reg_SP; - case PC: return reg_PC; - } - return 0; -} - -void i8080_write_reg16(reg_t reg, uint16_t value) { - switch (reg) { - case AF: reg8[A] = value>>8; reg8[FLAGS] = value; break; - case BC: reg8[B] = value>>8; reg8[C] = value; break; - case DE: reg8[D] = value>>8; reg8[E] = value; break; - case HL: reg8[H] = value>>8; reg8[L] = value; break; - case SP: reg_SP = value; break; - case PC: reg_PC = value; break; - } -} - -int i8080_exec(int cycles) { - uint8_t opcode, temp8, reg, reg2; - uint16_t temp16; - uint32_t temp32; - - while (cycles > 0) { - opcode = i8080_read(reg_PC++); - - switch (opcode) { - case 0x3A: //LDA a - load A from memory - temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8); - reg8[A] = i8080_read(temp16); - reg_PC += 2; - cycles -= 13; - break; - case 0x32: //STA a - store A to memory - temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8); - i8080_write(temp16, reg8[A]); - reg_PC += 2; - cycles -= 13; - break; - case 0x2A: //LHLD a - load H:L from memory - temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8); - reg8[L] = i8080_read(temp16++); - reg8[H] = i8080_read(temp16); - reg_PC += 2; - cycles -= 16; - break; - case 0x22: //SHLD a - store H:L to memory - temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8); - i8080_write(temp16++, reg8[L]); - i8080_write(temp16, reg8[H]); - reg_PC += 2; - cycles -= 16; - break; - case 0xEB: //XCHG - exchange DE and HL content - temp8 = reg8[D]; - reg8[D] = reg8[H]; - reg8[H] = temp8; - temp8 = reg8[E]; - reg8[E] = reg8[L]; - reg8[L] = temp8; - cycles -= 5; - break; - case 0xC6: //ADI # - add immediate to A - temp8 = i8080_read(reg_PC++); - temp16 = (uint16_t)reg8[A] + (uint16_t)temp8; - if (temp16 & 0xFF00) set_C(); else clear_C(); - calc_AC(reg8[A], temp8); - calc_SZP((uint8_t)temp16); - reg8[A] = (uint8_t)temp16; - cycles -= 7; - break; - case 0xCE: //ACI # - add immediate to A with carry - temp8 = i8080_read(reg_PC++); - temp16 = (uint16_t)reg8[A] + (uint16_t)temp8 + (uint16_t)test_C(); - if (test_C()) calc_AC_carry(reg8[A], temp8); else calc_AC(reg8[A], temp8); - if (temp16 & 0xFF00) set_C(); else clear_C(); - calc_SZP((uint8_t)temp16); - reg8[A] = (uint8_t)temp16; - cycles -= 7; - break; - case 0xD6: //SUI # - subtract immediate from A - temp8 = i8080_read(reg_PC++); - temp16 = (uint16_t)reg8[A] - (uint16_t)temp8; - if (((temp16 & 0x00FF) >= reg8[A]) && temp8) set_C(); else clear_C(); - calc_subAC(reg8[A], temp8); - calc_SZP((uint8_t)temp16); - reg8[A] = (uint8_t)temp16; - cycles -= 7; - break; - case 0x27: //DAA - decimal adjust accumulator - temp16 = reg8[A]; - if (((temp16 & 0x0F) > 0x09) || test_AC()) { - if (((temp16 & 0x0F) + 0x06) & 0xF0) set_AC(); else clear_AC(); - temp16 += 0x06; - if (temp16 & 0xFF00) set_C(); //can also cause carry to be set during addition to the low nibble - } - if (((temp16 & 0xF0) > 0x90) || test_C()) { - temp16 += 0x60; - if (temp16 & 0xFF00) set_C(); //doesn't clear it if this clause is false - } - calc_SZP((uint8_t)temp16); - reg8[A] = (uint8_t)temp16; - cycles -= 4; - break; - case 0xE6: //ANI # - AND immediate with A - temp8 = i8080_read(reg_PC++); - if ((reg8[A] | temp8) & 0x08) set_AC(); else clear_AC(); - reg8[A] &= temp8; - clear_C(); - calc_SZP(reg8[A]); - cycles -= 7; - break; - case 0xF6: //ORI # - OR immediate with A - reg8[A] |= i8080_read(reg_PC++); - clear_AC(); - clear_C(); - calc_SZP(reg8[A]); - cycles -= 7; - break; - case 0xEE: //XRI # - XOR immediate with A - reg8[A] ^= i8080_read(reg_PC++); - clear_AC(); - clear_C(); - calc_SZP(reg8[A]); - cycles -= 7; - break; - case 0xDE: //SBI # - subtract immediate from A with borrow - temp8 = i8080_read(reg_PC++); - temp16 = (uint16_t)reg8[A] - (uint16_t)temp8 - (uint16_t)test_C(); - if (test_C()) calc_subAC_borrow(reg8[A], temp8); else calc_subAC(reg8[A], temp8); - if (((temp16 & 0x00FF) >= reg8[A]) && (temp8 | test_C())) set_C(); else clear_C(); - calc_SZP((uint8_t)temp16); - reg8[A] = (uint8_t)temp16; - cycles -= 7; - break; - case 0xFE: //CPI # - compare immediate with A - temp8 = i8080_read(reg_PC++); - temp16 = (uint16_t)reg8[A] - (uint16_t)temp8; - if (((temp16 & 0x00FF) >= reg8[A]) && temp8) set_C(); else clear_C(); - calc_subAC(reg8[A], temp8); - calc_SZP((uint8_t)temp16); - cycles -= 7; - break; - case 0x07: //RLC - rotate A left - if (reg8[A] & 0x80) set_C(); else clear_C(); - reg8[A] = (reg8[A] >> 7) | (reg8[A] << 1); - cycles -= 4; - break; - case 0x0F: //RRC - rotate A right - if (reg8[A] & 0x01) set_C(); else clear_C(); - reg8[A] = (reg8[A] << 7) | (reg8[A] >> 1); - cycles -= 4; - break; - case 0x17: //RAL - rotate A left through carry - temp8 = test_C(); - if (reg8[A] & 0x80) set_C(); else clear_C(); - reg8[A] = (reg8[A] << 1) | temp8; - cycles -= 4; - break; - case 0x1F: //RAR - rotate A right through carry - temp8 = test_C(); - if (reg8[A] & 0x01) set_C(); else clear_C(); - reg8[A] = (reg8[A] >> 1) | (temp8 << 7); - cycles -= 4; - break; - case 0x2F: //CMA - compliment A - reg8[A] = ~reg8[A]; - cycles -= 4; - break; - case 0x3F: //CMC - compliment carry flag - reg8[FLAGS] ^= 1; - cycles -= 4; - break; - case 0x37: //STC - set carry flag - set_C(); - cycles -= 4; - break; - case 0xC7: //RST n - restart (call n*8) - case 0xD7: - case 0xE7: - case 0xF7: - case 0xCF: - case 0xDF: - case 0xEF: - case 0xFF: - i8080_push(reg_PC); - reg_PC = (uint16_t)((opcode >> 3) & 7) << 3; - cycles -= 11; - break; - case 0xE9: //PCHL - jump to address in H:L - reg_PC = reg16_HL; - cycles -= 5; - break; - case 0xE3: //XTHL - swap H:L with top word on stack - temp16 = i8080_pop(); - i8080_push(reg16_HL); - write16_RP(2, temp16); - cycles -= 18; - break; - case 0xF9: //SPHL - set SP to content of HL - reg_SP = reg16_HL; - cycles -= 5; - break; - case 0xDB: //IN p - read input port into A - reg8[A] = i8080_inport(i8080_read(reg_PC++)); - cycles -= 10; - break; - case 0xD3: //OUT p - write A to output port - i8080_outport(i8080_read(reg_PC++), reg8[A]); - cycles -= 10; - break; - case 0xFB: //EI - enable interrupts - INTE = 1; - cycles -= 4; - break; - case 0xF3: //DI - disbale interrupts - INTE = 0; - cycles -= 4; - break; - case 0x76: //HLT - halt processor - reg_PC--; - cycles -= 7; - break; - case 0x00: //NOP - no operation -#ifdef ALLOW_UNDEFINED - case 0x10: - case 0x20: - case 0x30: - case 0x08: - case 0x18: - case 0x28: - case 0x38: -#endif - cycles -= 4; - break; - case 0x40: case 0x50: case 0x60: case 0x70: //MOV D,S - move register to register - case 0x41: case 0x51: case 0x61: case 0x71: - case 0x42: case 0x52: case 0x62: case 0x72: - case 0x43: case 0x53: case 0x63: case 0x73: - case 0x44: case 0x54: case 0x64: case 0x74: - case 0x45: case 0x55: case 0x65: case 0x75: - case 0x46: case 0x56: case 0x66: - case 0x47: case 0x57: case 0x67: case 0x77: - case 0x48: case 0x58: case 0x68: case 0x78: - case 0x49: case 0x59: case 0x69: case 0x79: - case 0x4A: case 0x5A: case 0x6A: case 0x7A: - case 0x4B: case 0x5B: case 0x6B: case 0x7B: - case 0x4C: case 0x5C: case 0x6C: case 0x7C: - case 0x4D: case 0x5D: case 0x6D: case 0x7D: - case 0x4E: case 0x5E: case 0x6E: case 0x7E: - case 0x4F: case 0x5F: case 0x6F: case 0x7F: - reg = (opcode >> 3) & 7; - reg2 = opcode & 7; - i8080_write_reg8(reg, i8080_read_reg8(reg2)); - if ((reg == M) || (reg2 == M)) { - cycles -= 7; - } else { - cycles -= 5; - } - break; - case 0x06: //MVI D,# - move immediate to register - case 0x16: - case 0x26: - case 0x36: - case 0x0E: - case 0x1E: - case 0x2E: - case 0x3E: - reg = (opcode >> 3) & 7; - i8080_write_reg8(reg, i8080_read(reg_PC++)); - if (reg == M) { - cycles -= 10; - } else { - cycles -= 7; - } - break; - case 0x01: //LXI RP,# - load register pair immediate - case 0x11: - case 0x21: - case 0x31: - reg = (opcode >> 4) & 3; - write_RP(reg, i8080_read(reg_PC), i8080_read(reg_PC + 1)); - reg_PC += 2; - cycles -= 10; - break; - case 0x0A: //LDAX BC - load A indirect through BC - reg8[A] = i8080_read(reg16_BC); - cycles -= 7; - break; - case 0x1A: //LDAX DE - load A indirect through DE - reg8[A] = i8080_read(reg16_DE); - cycles -= 7; - break; - case 0x02: //STAX BC - store A indirect through BC - i8080_write(reg16_BC, reg8[A]); - cycles -= 7; - break; - case 0x12: //STAX DE - store A indirect through DE - i8080_write(reg16_DE, reg8[A]); - cycles -= 7; - break; - case 0x04: //INR D - increment register - case 0x14: - case 0x24: - case 0x34: - case 0x0C: - case 0x1C: - case 0x2C: - case 0x3C: - reg = (opcode >> 3) & 7; - temp8 = i8080_read_reg8(reg); //reg8[reg]; - calc_AC(temp8, 1); - calc_SZP(temp8 + 1); - i8080_write_reg8(reg, temp8 + 1); //reg8[reg]++; - if (reg == M) { - cycles -= 10; - } else { - cycles -= 5; - } - break; - case 0x05: //DCR D - decrement register - case 0x15: - case 0x25: - case 0x35: - case 0x0D: - case 0x1D: - case 0x2D: - case 0x3D: - reg = (opcode >> 3) & 7; - temp8 = i8080_read_reg8(reg); //reg8[reg]; - calc_subAC(temp8, 1); - calc_SZP(temp8 - 1); - i8080_write_reg8(reg, temp8 - 1); //reg8[reg]--; - if (reg == M) { - cycles -= 10; - } else { - cycles -= 5; - } - break; - case 0x03: //INX RP - increment register pair - case 0x13: - case 0x23: - case 0x33: - reg = (opcode >> 4) & 3; - write16_RP(reg, read_RP(reg) + 1); - cycles -= 5; - break; - case 0x0B: //DCX RP - decrement register pair - case 0x1B: - case 0x2B: - case 0x3B: - reg = (opcode >> 4) & 3; - write16_RP(reg, read_RP(reg) - 1); - cycles -= 5; - break; - case 0x09: //DAD RP - add register pair to HL - case 0x19: - case 0x29: - case 0x39: - reg = (opcode >> 4) & 3; - temp32 = (uint32_t)reg16_HL + (uint32_t)read_RP(reg); - write16_RP(2, (uint16_t)temp32); - if (temp32 & 0xFFFF0000) set_C(); else clear_C(); - cycles -= 10; - break; - case 0x80: //ADD S - add register or memory to A - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - reg = opcode & 7; - temp8 = i8080_read_reg8(reg); - temp16 = (uint16_t)reg8[A] + (uint16_t)temp8; - if (temp16 & 0xFF00) set_C(); else clear_C(); - calc_AC(reg8[A], temp8); - calc_SZP((uint8_t)temp16); - reg8[A] = (uint8_t)temp16; - if (reg == M) { - cycles -= 7; - } else { - cycles -= 4; - } - break; - case 0x88: //ADC S - add register or memory to A with carry - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - reg = opcode & 7; - temp8 = i8080_read_reg8(reg); - temp16 = (uint16_t)reg8[A] + (uint16_t)temp8 + (uint16_t)test_C(); - if (test_C()) calc_AC_carry(reg8[A], temp8); else calc_AC(reg8[A], temp8); - if (temp16 & 0xFF00) set_C(); else clear_C(); - calc_SZP((uint8_t)temp16); - reg8[A] = (uint8_t)temp16; - if (reg == M) { - cycles -= 7; - } else { - cycles -= 4; - } - break; - case 0x90: //SUB S - subtract register or memory from A - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - reg = opcode & 7; - temp8 = i8080_read_reg8(reg); - temp16 = (uint16_t)reg8[A] - (uint16_t)temp8; - if (((temp16 & 0x00FF) >= reg8[A]) && temp8) set_C(); else clear_C(); - calc_subAC(reg8[A], temp8); - calc_SZP((uint8_t)temp16); - reg8[A] = (uint8_t)temp16; - if (reg == M) { - cycles -= 7; - } else { - cycles -= 4; - } - break; - case 0x98: //SBB S - subtract register or memory from A with borrow - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - reg = opcode & 7; - temp8 = i8080_read_reg8(reg); - temp16 = (uint16_t)reg8[A] - (uint16_t)temp8 - (uint16_t)test_C(); - if (test_C()) calc_subAC_borrow(reg8[A], temp8); else calc_subAC(reg8[A], temp8); - if (((temp16 & 0x00FF) >= reg8[A]) && (temp8 | test_C())) set_C(); else clear_C(); - calc_SZP((uint8_t)temp16); - reg8[A] = (uint8_t)temp16; - if (reg == M) { - cycles -= 7; - } else { - cycles -= 4; - } - break; - case 0xA0: //ANA S - AND register with A - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - reg = opcode & 7; - temp8 = i8080_read_reg8(reg); - if ((reg8[A] | temp8) & 0x08) set_AC(); else clear_AC(); - reg8[A] &= temp8; - clear_C(); - calc_SZP(reg8[A]); - if (reg == M) { - cycles -= 7; - } else { - cycles -= 4; - } - break; - case 0xB0: //ORA S - OR register with A - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - reg = opcode & 7; - reg8[A] |= i8080_read_reg8(reg); - clear_AC(); - clear_C(); - calc_SZP(reg8[A]); - if (reg == M) { - cycles -= 7; - } else { - cycles -= 4; - } - break; - case 0xA8: //XRA S - XOR register with A - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - reg = opcode & 7; - reg8[A] ^= i8080_read_reg8(reg); - clear_AC(); - clear_C(); - calc_SZP(reg8[A]); - if (reg == M) { - cycles -= 7; - } else { - cycles -= 4; - } - break; - case 0xB8: //CMP S - compare register with A - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - reg = opcode & 7; - temp8 = i8080_read_reg8(reg); - temp16 = (uint16_t)reg8[A] - (uint16_t)temp8; - if (((temp16 & 0x00FF) >= reg8[A]) && temp8) set_C(); else clear_C(); - calc_subAC(reg8[A], temp8); - calc_SZP((uint8_t)temp16); - if (reg == M) { - cycles -= 7; - } else { - cycles -= 4; - } - break; - case 0xC3: //JMP a - unconditional jump -#ifdef ALLOW_UNDEFINED - case 0xCB: -#endif - temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8); - reg_PC = temp16; - cycles -= 10; - break; - case 0xC2: //Jccc - conditional jumps - case 0xCA: - case 0xD2: - case 0xDA: - case 0xE2: - case 0xEA: - case 0xF2: - case 0xFA: - temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8); - if (test_cond((opcode >> 3) & 7)) reg_PC = temp16; else reg_PC += 2; - cycles -= 10; - break; - case 0xCD: //CALL a - unconditional call -#ifdef ALLOW_UNDEFINED - case 0xDD: - case 0xED: - case 0xFD: -#endif - temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8); - i8080_push(reg_PC + 2); - reg_PC = temp16; - cycles -= 17; - break; - case 0xC4: //Cccc - conditional calls - case 0xCC: - case 0xD4: - case 0xDC: - case 0xE4: - case 0xEC: - case 0xF4: - case 0xFC: - temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8); - if (test_cond((opcode >> 3) & 7)) { - i8080_push(reg_PC + 2); - reg_PC = temp16; - cycles -= 17; - } else { - reg_PC += 2; - cycles -= 11; - } - break; - case 0xC9: //RET - unconditional return -#ifdef ALLOW_UNDEFINED - case 0xD9: -#endif - reg_PC = i8080_pop(); - cycles -= 10; - break; - case 0xC0: //Rccc - conditional returns - case 0xC8: - case 0xD0: - case 0xD8: - case 0xE0: - case 0xE8: - case 0xF0: - case 0xF8: - if (test_cond((opcode >> 3) & 7)) { - reg_PC = i8080_pop(); - cycles -= 11; - } else { - cycles -= 5; - } - break; - case 0xC5: //PUSH RP - push register pair on the stack - case 0xD5: - case 0xE5: - case 0xF5: - reg = (opcode >> 4) & 3; - i8080_push(read_RP_PUSHPOP(reg)); - cycles -= 11; - break; - case 0xC1: //POP RP - pop register pair from the stack - case 0xD1: - case 0xE1: - case 0xF1: - reg = (opcode >> 4) & 3; - write16_RP_PUSHPOP(reg, i8080_pop()); - cycles -= 10; - break; - -#ifndef ALLOW_UNDEFINED - default: - printf("UNRECOGNIZED INSTRUCTION @ %04Xh: %02X\n", reg_PC - 1, opcode); - exit(0); -#endif - } - - } - - return cycles; -} +/* + Intel 8080 emulator in C + Written by Mike Chambers, April 2018 + + Use this code for whatever you want. I don't care. It's officially public domain. + Credit would be appreciated. +*/ + +#include +#include +#include +#include "intel_8080_emulator.h" + +#define ALLOW_UNDEFINED + +#define reg16_PSW (((uint16_t)reg8[A] << 8) | (uint16_t)reg8[FLAGS]) +#define reg16_BC (((uint16_t)reg8[B] << 8) | (uint16_t)reg8[C]) +#define reg16_DE (((uint16_t)reg8[D] << 8) | (uint16_t)reg8[E]) +#define reg16_HL (((uint16_t)reg8[H] << 8) | (uint16_t)reg8[L]) + +uint8_t reg8[9], INTE = 0; +uint16_t reg_SP, reg_PC; + +#define set_S() reg8[FLAGS] |= 0x80 +#define set_Z() reg8[FLAGS] |= 0x40 +#define set_AC() reg8[FLAGS] |= 0x10 +#define set_P() reg8[FLAGS] |= 0x04 +#define set_C() reg8[FLAGS] |= 0x01 +#define clear_S() reg8[FLAGS] &= 0x7F +#define clear_Z() reg8[FLAGS] &= 0xBF +#define clear_AC() reg8[FLAGS] &= 0xEF +#define clear_P() reg8[FLAGS] &= 0xFB +#define clear_C() reg8[FLAGS] &= 0xFE +#define test_S() (reg8[FLAGS] & 0x80) +#define test_Z() (reg8[FLAGS] & 0x40) +#define test_AC() (reg8[FLAGS] & 0x10) +#define test_P() (reg8[FLAGS] & 0x04) +#define test_C() (reg8[FLAGS] & 0x01) + +static const uint8_t parity[0x100] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 +}; + +uint16_t read_RP(uint8_t rp) { + switch (rp) { + case 0x00: + return reg16_BC; + case 0x01: + return reg16_DE; + case 0x02: + return reg16_HL; + case 0x03: + return reg_SP; + } + return 0; +} + +uint16_t read_RP_PUSHPOP(uint8_t rp) { + switch (rp) { + case 0x00: + return reg16_BC; + case 0x01: + return reg16_DE; + case 0x02: + return reg16_HL; + case 0x03: + return (reg16_PSW | 0x02) & 0xFFD7; + } + return 0; +} + +void write_RP(uint8_t rp, uint8_t lb, uint8_t hb) { + switch (rp) { + case 0x00: + reg8[C] = lb; + reg8[B] = hb; + break; + case 0x01: + reg8[E] = lb; + reg8[D] = hb; + break; + case 0x02: + reg8[L] = lb; + reg8[H] = hb; + break; + case 0x03: + reg_SP = (uint16_t)lb | ((uint16_t)hb << 8); + break; + } +} + +void write16_RP(uint8_t rp, uint16_t value) { + switch (rp) { + case 0x00: + reg8[C] = value & 0x00FF; + reg8[B] = value >> 8; + break; + case 0x01: + reg8[E] = value & 0x00FF; + reg8[D] = value >> 8; + break; + case 0x02: + reg8[L] = value & 0x00FF; + reg8[H] = value >> 8; + break; + case 0x03: + reg_SP = value; + break; + } +} + +void write16_RP_PUSHPOP(uint8_t rp, uint16_t value) { + switch (rp) { + case 0x00: + reg8[C] = value & 0x00FF; + reg8[B] = value >> 8; + break; + case 0x01: + reg8[E] = value & 0x00FF; + reg8[D] = value >> 8; + break; + case 0x02: + reg8[L] = value & 0x00FF; + reg8[H] = value >> 8; + break; + case 0x03: + reg8[FLAGS] = ((value & 0x00FF) | 0x02) & 0xD7; + reg8[A] = value >> 8; + break; + } +} + +void calc_SZP(uint8_t value) { + if (value == 0) set_Z(); else clear_Z(); + if (value & 0x80) set_S(); else clear_S(); + if (parity[value]) set_P(); else clear_P(); +} + +void calc_AC(uint8_t val1, uint8_t val2) { + if (((val1 & 0x0F) + (val2 & 0x0F)) > 0x0F) { + set_AC(); + } else { + clear_AC(); + } +} + +void calc_AC_carry(uint8_t val1, uint8_t val2) { + if (((val1 & 0x0F) + (val2 & 0x0F)) >= 0x0F) { + set_AC(); + } else { + clear_AC(); + } +} + +void calc_subAC(int8_t val1, uint8_t val2) { + if ((val2 & 0x0F) <= (val1 & 0x0F)) { + set_AC(); + } else { + clear_AC(); + } +} + +void calc_subAC_borrow(int8_t val1, uint8_t val2) { + if ((val2 & 0x0F) < (val1 & 0x0F)) { + set_AC(); + } else { + clear_AC(); + } +} + +uint8_t test_cond(uint8_t code) { + switch (code) { + case 0: //Z not set + if (!test_Z()) return 1; else return 0; + case 1: //Z set + if (test_Z()) return 1; else return 0; + case 2: //C not set + if (!test_C()) return 1; else return 0; + case 3: //C set + if (test_C()) return 1; else return 0; + case 4: //P not set + if (!test_P()) return 1; else return 0; + case 5: //P set + if (test_P()) return 1; else return 0; + case 6: //S not set + if (!test_S()) return 1; else return 0; + case 7: //S set + if (test_S()) return 1; else return 0; + } + return 0; +} + +void i8080_push(uint16_t value) { + i8080_write(--reg_SP, value >> 8); + i8080_write(--reg_SP, (uint8_t)value); +} + +uint16_t i8080_pop() { + uint16_t temp; + temp = i8080_read(reg_SP++); + temp |= (uint16_t)i8080_read(reg_SP++) << 8; + return temp; +} + +void i8080_interrupt(uint8_t n) { + if (!INTE) return; + i8080_push(reg_PC); + reg_PC = (uint16_t)n << 3; + INTE = 0; +} + +void i8080_jump(uint16_t addr) { + reg_PC = addr; +} + +void i8080_reset() { + reg_PC = reg_SP = 0x0000; + //reg8[FLAGS] = 0x02; +} + +void i8080_write_reg8(reg_t reg, uint8_t value) { + if (reg == M) { + i8080_write(reg16_HL, value); + } else { + reg8[reg] = value; + } +} + +uint8_t i8080_read_reg8(reg_t reg) { + if (reg == M) { + return i8080_read(reg16_HL); + } else { + return reg8[reg]; + } +} + +uint16_t i8080_read_reg16(reg_t reg) { + switch (reg) { + case AF: return reg16_PSW; + case BC: return reg16_BC; + case DE: return reg16_DE; + case HL: return reg16_HL; + case SP: return reg_SP; + case PC: return reg_PC; + } + return 0; +} + +void i8080_write_reg16(reg_t reg, uint16_t value) { + switch (reg) { + case AF: reg8[A] = value>>8; reg8[FLAGS] = value; break; + case BC: reg8[B] = value>>8; reg8[C] = value; break; + case DE: reg8[D] = value>>8; reg8[E] = value; break; + case HL: reg8[H] = value>>8; reg8[L] = value; break; + case SP: reg_SP = value; break; + case PC: reg_PC = value; break; + } +} + +int i8080_exec(int cycles) { + uint8_t opcode, temp8, reg, reg2; + uint16_t temp16; + uint32_t temp32; + + while (cycles > 0) { + opcode = i8080_read(reg_PC++); + + switch (opcode) { + case 0x3A: //LDA a - load A from memory + temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8); + reg8[A] = i8080_read(temp16); + reg_PC += 2; + cycles -= 13; + break; + case 0x32: //STA a - store A to memory + temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8); + i8080_write(temp16, reg8[A]); + reg_PC += 2; + cycles -= 13; + break; + case 0x2A: //LHLD a - load H:L from memory + temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8); + reg8[L] = i8080_read(temp16++); + reg8[H] = i8080_read(temp16); + reg_PC += 2; + cycles -= 16; + break; + case 0x22: //SHLD a - store H:L to memory + temp16 = (uint16_t)i8080_read(reg_PC) | ((uint16_t)i8080_read(reg_PC+1)<<8); + i8080_write(temp16++, reg8[L]); + i8080_write(temp16, reg8[H]); + reg_PC += 2; + cycles -= 16; + break; + case 0xEB: //XCHG - exchange DE and HL content + temp8 = reg8[D]; + reg8[D] = reg8[H]; + reg8[H] = temp8; + temp8 = reg8[E]; + reg8[E] = reg8[L]; + reg8[L] = temp8; + cycles -= 5; + break; + case 0xC6: //ADI # - add immediate to A + temp8 = i8080_read(reg_PC++); + temp16 = (uint16_t)reg8[A] + (uint16_t)temp8; + if (temp16 & 0xFF00) set_C(); else clear_C(); + calc_AC(reg8[A], temp8); + calc_SZP((uint8_t)temp16); + reg8[A] = (uint8_t)temp16; + cycles -= 7; + break; + case 0xCE: //ACI # - add immediate to A with carry + temp8 = i8080_read(reg_PC++); + temp16 = (uint16_t)reg8[A] + (uint16_t)temp8 + (uint16_t)test_C(); + if (test_C()) calc_AC_carry(reg8[A], temp8); else calc_AC(reg8[A], temp8); + if (temp16 & 0xFF00) set_C(); else clear_C(); + calc_SZP((uint8_t)temp16); + reg8[A] = (uint8_t)temp16; + cycles -= 7; + break; + case 0xD6: //SUI # - subtract immediate from A + temp8 = i8080_read(reg_PC++); + temp16 = (uint16_t)reg8[A] - (uint16_t)temp8; + if (((temp16 & 0x00FF) >= reg8[A]) && temp8) set_C(); else clear_C(); + calc_subAC(reg8[A], temp8); + calc_SZP((uint8_t)temp16); + reg8[A] = (uint8_t)temp16; + cycles -= 7; + break; + case 0x27: //DAA - decimal adjust accumulator + temp16 = reg8[A]; + if (((temp16 & 0x0F) > 0x09) || test_AC()) { + if (((temp16 & 0x0F) + 0x06) & 0xF0) set_AC(); else clear_AC(); + temp16 += 0x06; + if (temp16 & 0xFF00) set_C(); //can also cause carry to be set during addition to the low nibble + } + if (((temp16 & 0xF0) > 0x90) || test_C()) { + temp16 += 0x60; + if (temp16 & 0xFF00) set_C(); //doesn't clear it if this clause is false + } + calc_SZP((uint8_t)temp16); + reg8[A] = (uint8_t)temp16; + cycles -= 4; + break; + case 0xE6: //ANI # - AND immediate with A + temp8 = i8080_read(reg_PC++); + if ((reg8[A] | temp8) & 0x08) set_AC(); else clear_AC(); + reg8[A] &= temp8; + clear_C(); + calc_SZP(reg8[A]); + cycles -= 7; + break; + case 0xF6: //ORI # - OR immediate with A + reg8[A] |= i8080_read(reg_PC++); + clear_AC(); + clear_C(); + calc_SZP(reg8[A]); + cycles -= 7; + break; + case 0xEE: //XRI # - XOR immediate with A + reg8[A] ^= i8080_read(reg_PC++); + clear_AC(); + clear_C(); + calc_SZP(reg8[A]); + cycles -= 7; + break; + case 0xDE: //SBI # - subtract immediate from A with borrow + temp8 = i8080_read(reg_PC++); + temp16 = (uint16_t)reg8[A] - (uint16_t)temp8 - (uint16_t)test_C(); + if (test_C()) calc_subAC_borrow(reg8[A], temp8); else calc_subAC(reg8[A], temp8); + if (((temp16 & 0x00FF) >= reg8[A]) && (temp8 | test_C())) set_C(); else clear_C(); + calc_SZP((uint8_t)temp16); + reg8[A] = (uint8_t)temp16; + cycles -= 7; + break; + case 0xFE: //CPI # - compare immediate with A + temp8 = i8080_read(reg_PC++); + temp16 = (uint16_t)reg8[A] - (uint16_t)temp8; + if (((temp16 & 0x00FF) >= reg8[A]) && temp8) set_C(); else clear_C(); + calc_subAC(reg8[A], temp8); + calc_SZP((uint8_t)temp16); + cycles -= 7; + break; + case 0x07: //RLC - rotate A left + if (reg8[A] & 0x80) set_C(); else clear_C(); + reg8[A] = (reg8[A] >> 7) | (reg8[A] << 1); + cycles -= 4; + break; + case 0x0F: //RRC - rotate A right + if (reg8[A] & 0x01) set_C(); else clear_C(); + reg8[A] = (reg8[A] << 7) | (reg8[A] >> 1); + cycles -= 4; + break; + case 0x17: //RAL - rotate A left through carry + temp8 = test_C(); + if (reg8[A] & 0x80) set_C(); else clear_C(); + reg8[A] = (reg8[A] << 1) | temp8; + cycles -= 4; + break; + case 0x1F: //RAR - rotate A right through carry + temp8 = test_C(); + if (reg8[A] & 0x01) set_C(); else clear_C(); + reg8[A] = (reg8[A] >> 1) | (temp8 << 7); + cycles -= 4; + break; + case 0x2F: //CMA - compliment A + reg8[A] = ~reg8[A]; + cycles -= 4; + break; + case 0x3F: //CMC - compliment carry flag + reg8[FLAGS] ^= 1; + cycles -= 4; + break; + case 0x37: //STC - set carry flag + set_C(); + cycles -= 4; + break; + case 0xC7: //RST n - restart (call n*8) + case 0xD7: + case 0xE7: + case 0xF7: + case 0xCF: + case 0xDF: + case 0xEF: + case 0xFF: + i8080_push(reg_PC); + reg_PC = (uint16_t)((opcode >> 3) & 7) << 3; + cycles -= 11; + break; + case 0xE9: //PCHL - jump to address in H:L + reg_PC = reg16_HL; + cycles -= 5; + break; + case 0xE3: //XTHL - swap H:L with top word on stack + temp16 = i8080_pop(); + i8080_push(reg16_HL); + write16_RP(2, temp16); + cycles -= 18; + break; + case 0xF9: //SPHL - set SP to content of HL + reg_SP = reg16_HL; + cycles -= 5; + break; + case 0xDB: //IN p - read input port into A + reg8[A] = i8080_inport(i8080_read(reg_PC++)); + cycles -= 10; + break; + case 0xD3: //OUT p - write A to output port + i8080_outport(i8080_read(reg_PC++), reg8[A]); + cycles -= 10; + break; + case 0xFB: //EI - enable interrupts + INTE = 1; + cycles -= 4; + break; + case 0xF3: //DI - disbale interrupts + INTE = 0; + cycles -= 4; + break; + case 0x76: //HLT - halt processor + reg_PC--; + cycles -= 7; + break; + case 0x00: //NOP - no operation +#ifdef ALLOW_UNDEFINED + case 0x10: + case 0x20: + case 0x30: + case 0x08: + case 0x18: + case 0x28: + case 0x38: +#endif + cycles -= 4; + break; + case 0x40: case 0x50: case 0x60: case 0x70: //MOV D,S - move register to register + case 0x41: case 0x51: case 0x61: case 0x71: + case 0x42: case 0x52: case 0x62: case 0x72: + case 0x43: case 0x53: case 0x63: case 0x73: + case 0x44: case 0x54: case 0x64: case 0x74: + case 0x45: case 0x55: case 0x65: case 0x75: + case 0x46: case 0x56: case 0x66: + case 0x47: case 0x57: case 0x67: case 0x77: + case 0x48: case 0x58: case 0x68: case 0x78: + case 0x49: case 0x59: case 0x69: case 0x79: + case 0x4A: case 0x5A: case 0x6A: case 0x7A: + case 0x4B: case 0x5B: case 0x6B: case 0x7B: + case 0x4C: case 0x5C: case 0x6C: case 0x7C: + case 0x4D: case 0x5D: case 0x6D: case 0x7D: + case 0x4E: case 0x5E: case 0x6E: case 0x7E: + case 0x4F: case 0x5F: case 0x6F: case 0x7F: + reg = (opcode >> 3) & 7; + reg2 = opcode & 7; + i8080_write_reg8(reg, i8080_read_reg8(reg2)); + if ((reg == M) || (reg2 == M)) { + cycles -= 7; + } else { + cycles -= 5; + } + break; + case 0x06: //MVI D,# - move immediate to register + case 0x16: + case 0x26: + case 0x36: + case 0x0E: + case 0x1E: + case 0x2E: + case 0x3E: + reg = (opcode >> 3) & 7; + i8080_write_reg8(reg, i8080_read(reg_PC++)); + if (reg == M) { + cycles -= 10; + } else { + cycles -= 7; + } + break; + case 0x01: //LXI RP,# - load register pair immediate + case 0x11: + case 0x21: + case 0x31: + reg = (opcode >> 4) & 3; + write_RP(reg, i8080_read(reg_PC), i8080_read(reg_PC + 1)); + reg_PC += 2; + cycles -= 10; + break; + case 0x0A: //LDAX BC - load A indirect through BC + reg8[A] = i8080_read(reg16_BC); + cycles -= 7; + break; + case 0x1A: //LDAX DE - load A indirect through DE + reg8[A] = i8080_read(reg16_DE); + cycles -= 7; + break; + case 0x02: //STAX BC - store A indirect through BC + i8080_write(reg16_BC, reg8[A]); + cycles -= 7; + break; + case 0x12: //STAX DE - store A indirect through DE + i8080_write(reg16_DE, reg8[A]); + cycles -= 7; + break; + case 0x04: //INR D - increment register + case 0x14: + case 0x24: + case 0x34: + case 0x0C: + case 0x1C: + case 0x2C: + case 0x3C: + reg = (opcode >> 3) & 7; + temp8 = i8080_read_reg8(reg); //reg8[reg]; + calc_AC(temp8, 1); + calc_SZP(temp8 + 1); + i8080_write_reg8(reg, temp8 + 1); //reg8[reg]++; + if (reg == M) { + cycles -= 10; + } else { + cycles -= 5; + } + break; + case 0x05: //DCR D - decrement register + case 0x15: + case 0x25: + case 0x35: + case 0x0D: + case 0x1D: + case 0x2D: + case 0x3D: + reg = (opcode >> 3) & 7; + temp8 = i8080_read_reg8(reg); //reg8[reg]; + calc_subAC(temp8, 1); + calc_SZP(temp8 - 1); + i8080_write_reg8(reg, temp8 - 1); //reg8[reg]--; + if (reg == M) { + cycles -= 10; + } else { + cycles -= 5; + } + break; + case 0x03: //INX RP - increment register pair + case 0x13: + case 0x23: + case 0x33: + reg = (opcode >> 4) & 3; + write16_RP(reg, read_RP(reg) + 1); + cycles -= 5; + break; + case 0x0B: //DCX RP - decrement register pair + case 0x1B: + case 0x2B: + case 0x3B: + reg = (opcode >> 4) & 3; + write16_RP(reg, read_RP(reg) - 1); + cycles -= 5; + break; + case 0x09: //DAD RP - add register pair to HL + case 0x19: + case 0x29: + case 0x39: + reg = (opcode >> 4) & 3; + temp32 = (uint32_t)reg16_HL + (uint32_t)read_RP(reg); + write16_RP(2, (uint16_t)temp32); + if (temp32 & 0xFFFF0000) set_C(); else clear_C(); + cycles -= 10; + break; + case 0x80: //ADD S - add register or memory to A + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + reg = opcode & 7; + temp8 = i8080_read_reg8(reg); + temp16 = (uint16_t)reg8[A] + (uint16_t)temp8; + if (temp16 & 0xFF00) set_C(); else clear_C(); + calc_AC(reg8[A], temp8); + calc_SZP((uint8_t)temp16); + reg8[A] = (uint8_t)temp16; + if (reg == M) { + cycles -= 7; + } else { + cycles -= 4; + } + break; + case 0x88: //ADC S - add register or memory to A with carry + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + reg = opcode & 7; + temp8 = i8080_read_reg8(reg); + temp16 = (uint16_t)reg8[A] + (uint16_t)temp8 + (uint16_t)test_C(); + if (test_C()) calc_AC_carry(reg8[A], temp8); else calc_AC(reg8[A], temp8); + if (temp16 & 0xFF00) set_C(); else clear_C(); + calc_SZP((uint8_t)temp16); + reg8[A] = (uint8_t)temp16; + if (reg == M) { + cycles -= 7; + } else { + cycles -= 4; + } + break; + case 0x90: //SUB S - subtract register or memory from A + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + reg = opcode & 7; + temp8 = i8080_read_reg8(reg); + temp16 = (uint16_t)reg8[A] - (uint16_t)temp8; + if (((temp16 & 0x00FF) >= reg8[A]) && temp8) set_C(); else clear_C(); + calc_subAC(reg8[A], temp8); + calc_SZP((uint8_t)temp16); + reg8[A] = (uint8_t)temp16; + if (reg == M) { + cycles -= 7; + } else { + cycles -= 4; + } + break; + case 0x98: //SBB S - subtract register or memory from A with borrow + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + reg = opcode & 7; + temp8 = i8080_read_reg8(reg); + temp16 = (uint16_t)reg8[A] - (uint16_t)temp8 - (uint16_t)test_C(); + if (test_C()) calc_subAC_borrow(reg8[A], temp8); else calc_subAC(reg8[A], temp8); + if (((temp16 & 0x00FF) >= reg8[A]) && (temp8 | test_C())) set_C(); else clear_C(); + calc_SZP((uint8_t)temp16); + reg8[A] = (uint8_t)temp16; + if (reg == M) { + cycles -= 7; + } else { + cycles -= 4; + } + break; + case 0xA0: //ANA S - AND register with A + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + reg = opcode & 7; + temp8 = i8080_read_reg8(reg); + if ((reg8[A] | temp8) & 0x08) set_AC(); else clear_AC(); + reg8[A] &= temp8; + clear_C(); + calc_SZP(reg8[A]); + if (reg == M) { + cycles -= 7; + } else { + cycles -= 4; + } + break; + case 0xB0: //ORA S - OR register with A + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + reg = opcode & 7; + reg8[A] |= i8080_read_reg8(reg); + clear_AC(); + clear_C(); + calc_SZP(reg8[A]); + if (reg == M) { + cycles -= 7; + } else { + cycles -= 4; + } + break; + case 0xA8: //XRA S - XOR register with A + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + reg = opcode & 7; + reg8[A] ^= i8080_read_reg8(reg); + clear_AC(); + clear_C(); + calc_SZP(reg8[A]); + if (reg == M) { + cycles -= 7; + } else { + cycles -= 4; + } + break; + case 0xB8: //CMP S - compare register with A + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + reg = opcode & 7; + temp8 = i8080_read_reg8(reg); + temp16 = (uint16_t)reg8[A] - (uint16_t)temp8; + if (((temp16 & 0x00FF) >= reg8[A]) && temp8) set_C(); else clear_C(); + calc_subAC(reg8[A], temp8); + calc_SZP((uint8_t)temp16); + if (reg == M) { + cycles -= 7; + } else { + cycles -= 4; + } + break; + case 0xC3: //JMP a - unconditional jump +#ifdef ALLOW_UNDEFINED + case 0xCB: +#endif + temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8); + reg_PC = temp16; + cycles -= 10; + break; + case 0xC2: //Jccc - conditional jumps + case 0xCA: + case 0xD2: + case 0xDA: + case 0xE2: + case 0xEA: + case 0xF2: + case 0xFA: + temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8); + if (test_cond((opcode >> 3) & 7)) reg_PC = temp16; else reg_PC += 2; + cycles -= 10; + break; + case 0xCD: //CALL a - unconditional call +#ifdef ALLOW_UNDEFINED + case 0xDD: + case 0xED: + case 0xFD: +#endif + temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8); + i8080_push(reg_PC + 2); + reg_PC = temp16; + cycles -= 17; + break; + case 0xC4: //Cccc - conditional calls + case 0xCC: + case 0xD4: + case 0xDC: + case 0xE4: + case 0xEC: + case 0xF4: + case 0xFC: + temp16 = (uint16_t)i8080_read(reg_PC) | (((uint16_t)i8080_read(reg_PC + 1)) << 8); + if (test_cond((opcode >> 3) & 7)) { + i8080_push(reg_PC + 2); + reg_PC = temp16; + cycles -= 17; + } else { + reg_PC += 2; + cycles -= 11; + } + break; + case 0xC9: //RET - unconditional return +#ifdef ALLOW_UNDEFINED + case 0xD9: +#endif + reg_PC = i8080_pop(); + cycles -= 10; + break; + case 0xC0: //Rccc - conditional returns + case 0xC8: + case 0xD0: + case 0xD8: + case 0xE0: + case 0xE8: + case 0xF0: + case 0xF8: + if (test_cond((opcode >> 3) & 7)) { + reg_PC = i8080_pop(); + cycles -= 11; + } else { + cycles -= 5; + } + break; + case 0xC5: //PUSH RP - push register pair on the stack + case 0xD5: + case 0xE5: + case 0xF5: + reg = (opcode >> 4) & 3; + i8080_push(read_RP_PUSHPOP(reg)); + cycles -= 11; + break; + case 0xC1: //POP RP - pop register pair from the stack + case 0xD1: + case 0xE1: + case 0xF1: + reg = (opcode >> 4) & 3; + write16_RP_PUSHPOP(reg, i8080_pop()); + cycles -= 10; + break; + +#ifndef ALLOW_UNDEFINED + default: + printf("UNRECOGNIZED INSTRUCTION @ %04Xh: %02X\n", reg_PC - 1, opcode); + exit(0); +#endif + } + + } + + return cycles; +} diff --git a/plat/linux68k/emu/sim.h b/plat/linux68k/emu/sim.h index f0f9b0b61..e778006b4 100755 --- a/plat/linux68k/emu/sim.h +++ b/plat/linux68k/emu/sim.h @@ -1,15 +1,15 @@ -#ifndef SIM__HEADER -#define SIM__HEADER - -unsigned int cpu_read_byte(unsigned int address); -unsigned int cpu_read_word(unsigned int address); -unsigned int cpu_read_long(unsigned int address); -void cpu_write_byte(unsigned int address, unsigned int value); -void cpu_write_word(unsigned int address, unsigned int value); -void cpu_write_long(unsigned int address, unsigned int value); -void cpu_pulse_reset(void); -void cpu_set_fc(unsigned int fc); -int cpu_irq_ack(int level); -void cpu_instr_callback(int pc); - -#endif /* SIM__HEADER */ +#ifndef SIM__HEADER +#define SIM__HEADER + +unsigned int cpu_read_byte(unsigned int address); +unsigned int cpu_read_word(unsigned int address); +unsigned int cpu_read_long(unsigned int address); +void cpu_write_byte(unsigned int address, unsigned int value); +void cpu_write_word(unsigned int address, unsigned int value); +void cpu_write_long(unsigned int address, unsigned int value); +void cpu_pulse_reset(void); +void cpu_set_fc(unsigned int fc); +int cpu_irq_ack(int level); +void cpu_instr_callback(int pc); + +#endif /* SIM__HEADER */ diff --git a/util/make/README b/util/make/README index 240615627..e015620de 100644 --- a/util/make/README +++ b/util/make/README @@ -1,45 +1,45 @@ -Following is a repost of the public domain 'make' that I posted -to net.sources a couple of months ago. I have fixed a few bugs, and -added some more features, and the resulting changes amounted to -about as much text as the whole program (hence the repost). - -For those that missed the net.sources posting, this is a public domain -re-implementation of the UNIX make program. There is no manual included; -for documentation, refer to a UNIX manual, or the source. - -Here is a list of the changes made: - -i) If '-' (ignore) or '@' (silent) where used at the start - of a command, their effect was not turned off for the following - commands. -ii) A special target (.SUFFIXES, .PRECIOUS) or a rule (.c.o, .a.o), - if first in the file would be taken as the default target. - This resulted in error messages like "Don't know how to - make .c", because things like .SUFFIXES were being made. - This was further complicated by --- -iii) Special target lines with no dependents (ie. .SUFFIXES:\n) - were not clearing out the existing dependents like - they should. -iv) Default rules could not be redefined because of the error - checking for commands being defined twice. Now you are - allowed to define a target beinging with '.', having - no dependents with commands. -v) The -q option didn't do the time comparison correctly, - or clear the variable used to keep track of this. Thus - it didn't work very well. -vi) The syntax ${..} for macro's supported by UNIX make was - not supported. -vii) There wuz a couple of spelling errors. -viii) When make checked for implicit rules on targets without - a suffix, there were problems. (Note: The ~ feature of - UNIX make wasn't and still isn't supported) -ix) The -n option did not print @ lines like it was supposed to. -x) :: added. (See UNIX manual) -xi) $? added. (see UNIX manual) - -Hacked further by Ceriel Jacobs to make it work better. Use this "make" to -install ACK under Microsoft Xenix V3.2. Some of the makefiles are just too -big for the Xenix "make". Strange, they work on a PDP-11 ... - -Made it almost ISO C90 and POSIX portable by Carl Eric Codere, and -also made it safer by using correct datatypes on some library calls. +Following is a repost of the public domain 'make' that I posted +to net.sources a couple of months ago. I have fixed a few bugs, and +added some more features, and the resulting changes amounted to +about as much text as the whole program (hence the repost). + +For those that missed the net.sources posting, this is a public domain +re-implementation of the UNIX make program. There is no manual included; +for documentation, refer to a UNIX manual, or the source. + +Here is a list of the changes made: + +i) If '-' (ignore) or '@' (silent) where used at the start + of a command, their effect was not turned off for the following + commands. +ii) A special target (.SUFFIXES, .PRECIOUS) or a rule (.c.o, .a.o), + if first in the file would be taken as the default target. + This resulted in error messages like "Don't know how to + make .c", because things like .SUFFIXES were being made. + This was further complicated by --- +iii) Special target lines with no dependents (ie. .SUFFIXES:\n) + were not clearing out the existing dependents like + they should. +iv) Default rules could not be redefined because of the error + checking for commands being defined twice. Now you are + allowed to define a target beinging with '.', having + no dependents with commands. +v) The -q option didn't do the time comparison correctly, + or clear the variable used to keep track of this. Thus + it didn't work very well. +vi) The syntax ${..} for macro's supported by UNIX make was + not supported. +vii) There wuz a couple of spelling errors. +viii) When make checked for implicit rules on targets without + a suffix, there were problems. (Note: The ~ feature of + UNIX make wasn't and still isn't supported) +ix) The -n option did not print @ lines like it was supposed to. +x) :: added. (See UNIX manual) +xi) $? added. (see UNIX manual) + +Hacked further by Ceriel Jacobs to make it work better. Use this "make" to +install ACK under Microsoft Xenix V3.2. Some of the makefiles are just too +big for the Xenix "make". Strange, they work on a PDP-11 ... + +Made it almost ISO C90 and POSIX portable by Carl Eric Codere, and +also made it safer by using correct datatypes on some library calls. diff --git a/util/topgen/topgen.g b/util/topgen/topgen.g index 0dc923929..72c08526c 100644 --- a/util/topgen/topgen.g +++ b/util/topgen/topgen.g @@ -1,349 +1,349 @@ -/* $Id$ */ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -/* t o p g e n . g - * - * Grammar of optimizer description, and some code generation - */ - -%token LETTER, DIGIT, OTHER, SPACE; -%token LINE_TERMINATOR, OPERAND_SEPARATOR, INSTRUCTION_SEPARATOR, - PATTERN_SEPARATOR, OPEN_BRACKET, CLOSE_BRACKET; -%lexical LLlex; -%start LLparse, optim_description; - -{ -#include -#include -#include -#include "token.h" -#include "symtab.h" -#include "misc.h" -#include "hash.h" -#include "pattern.h" - -char idbuf[BUFSIZ], buf[BUFSIZ]; -int countid; /* # of variables */ -int countpat; /* # of patterns */ -static int patlen; /* Maximum number of instructions in pattern */ -static int maxoperand; /* Maximum number of operands of instruction */ -extern FILE *input; /* file descriptor of inputfile */ - - - -extern int onlyspace(char* s); -extern void error(char *s, char* s1); - - -} - -optim_description - { struct symtab *p; } : - SPACE* parameters - { p = findident("MAXOP",LOOKING,&deftable); - if (p == 0) maxoperand = 2; /* default */ - else maxoperand = p->s_num; - } - separator SPACE* mode_definitions - separator SPACE* patterns - separator - { register int c; - fprintf(genc, linedir, lineno, inpfile); - while ((c = getc(input)) != EOF) { - putc(c,genc); - } - } -; - -parameters : - [ parameter_line | declaration_block ]* -; - -parameter_line - { struct symtab *p; - int lin; - } : - identifier - { p = findident(idbuf,ENTERING,&deftable);} - SPACE - { lin = lineno;} - value - { p->s_num = atoi(buf);} - /* This action in fact only needed for MAXOP */ - LINE_TERMINATOR - SPACE* - { fprintf(genh, linedir, lin, inpfile); - fprintf(genh,"#define %s %s\n",p->s_name,buf);} -; - -value - { char *p1 = buf;} : - [ - [ OPEN_BRACKET - | CLOSE_BRACKET - | OPERAND_SEPARATOR - | PATTERN_SEPARATOR - | INSTRUCTION_SEPARATOR - | SPACE - | LETTER - | DIGIT - | OTHER - | '%' - ] - { *p1++ = dot.t_attrib;} - ]* - { *p1 = '\0';} -; - -declaration_block : - OPEN_BRACKET - { fprintf(genh, linedir, lineno, inpfile);} - [ - [ LINE_TERMINATOR - | OPERAND_SEPARATOR - | PATTERN_SEPARATOR - | INSTRUCTION_SEPARATOR - | SPACE - | LETTER - | DIGIT - | OTHER - | '%' - ] - { putc(dot.t_attrib, genh);} - ]* - CLOSE_BRACKET - SPACE* - { putc('\n', genh);} -; - -mode_definitions - { int lin; } : - { fputs("int tok_chk(int varno) {\n\tint r;\n", genc); - fputs("\tchar *VAL;\n\n",genc); - fputs("\tVAL = var[varno].value;\n",genc); - fputs("\tswitch(varno) {\n",genc); - } - [ - token_list - constraint(&lin) - { fprintf(genc,linedir,lin,inpfile); - fprintf(genc,"\t\tr = (%s); break;\n",buf); - } - LINE_TERMINATOR - SPACE* - ]* - { fputs("\tdefault :\n\t\tassert(0);\n",genc); - fputs("\t}\n\treturn r;\n}\n\n",genc); - } -; - -token_list : - new_identifier - SPACE* - [ - OPERAND_SEPARATOR - SPACE* - new_identifier - SPACE* - ]* -; - -new_identifier - { struct symtab *p;} : - identifier - { p = findident(idbuf,ENTERING,&idtable); - p->s_num = ++countid; - fprintf(genc,"\tcase %d:\n", countid); - } -; - -constraint (int *lin;) - { char *p = buf; } : - OPEN_BRACKET - { *lin = lineno;} - [ - [ LINE_TERMINATOR - | OPERAND_SEPARATOR - | PATTERN_SEPARATOR - | INSTRUCTION_SEPARATOR - | LETTER - | DIGIT - | SPACE - | OTHER - | '%' - ] - { *p++ = dot.t_attrib;} - ]* - { *p = '\0'; - if (onlyspace(buf)) strcpy(buf,"TRUE"); - } - CLOSE_BRACKET - SPACE* -; - -patterns - { int lin; - char *constr; - int np, nr; - } : -[ - { countpat++; - constr = (char *) 0; - fprintf(genc,"struct instr_descr pat%d[] = {\n", - countpat); - } - instruction_list(&np) - { if (np > patlen) patlen = np; - fputs("\n};\n\n",genc); - } - [ - constraint(&lin) - { /* Save the constraint, we need it later on */ - constr = malloc((unsigned)(strlen(buf)+1)); - strcpy(constr,buf); - } - ]? - PATTERN_SEPARATOR - { fprintf(genc,"struct instr_descr rep%d[] = {\n", - countpat); - } - replacement(&nr) - { fputs("\n};\n\n",genc);} - LINE_TERMINATOR - SPACE* - { addpattern(constr,lin,np,nr);} -]* - { printhashtable(); - printpatterns(); - fprintf(genh,"#define NRVARS %d\n",countid); - fprintf(genh,"#define NRPATTERNS %d\n",countpat); - fprintf(genh,"#define MIN_WINDOW_SIZE %d\n", - patlen+3); - fclose(genh); - } -; - -instruction_list(int *n;) : - instruction(1) - { *n = 1;} - [ - INSTRUCTION_SEPARATOR - { fputs(",\n",genc);} - SPACE* - instruction(0) - { *n += 1;} - ]* -; - -instruction(int opt;) - { int count = 0;} : - opcode(opt) - { if (strcmp(buf,"ANY") != 0) { - fprintf(genc,"\t{\"%s\", {",buf); - } - else fputs("\t{(char *) 0, {",genc); - count = 0; - } - [ - operand(' ') - { count = 1;} - [ - OPERAND_SEPARATOR - { count++;} - SPACE* - operand(',') - ]* - { if (count > maxoperand) { - error("Too many operands",""); - } - } - ]? - { while (count++ < maxoperand) { - fprintf(genc,"%c{\"\",-1,\"\"}",count == 1 ? ' ' : ','); - } - putc('}',genc); - putc('}',genc); - } -; - -opcode(int opt;) - { char *p = buf;} : - [ - [ LETTER - | DIGIT - | OTHER - ] - { *p++ = dot.t_attrib;} - ]+ - SPACE+ - { *p = '\0'; - if (opt) addtohashtable(buf,countpat); - } -; - -operand(int c;) - { register struct symtab *p = 0;} : - { fprintf(genc, "%c{\"", c);} - [ - identifier - { if (!p) { - p = findident(idbuf,LOOKING,&idtable); - if (p) fprintf(genc,"\",%d,\"",p->s_num); - else fputs(idbuf,genc); - } - else fputs(idbuf,genc); - } - | DIGIT - { putc(dot.t_attrib,genc);} - | OTHER - { putc(dot.t_attrib,genc);} - ]+ - { if (p) fputs("\"}",genc); - else fputs("\",0,\"\"}",genc); - } - SPACE* -; - -replacement (int *n;) - {register int i;} : - SPACE* - { *n = 0;} - [ - instruction(0) - { *n = 1;} - [ - INSTRUCTION_SEPARATOR - { fputs(",\n", genc);} - SPACE* - instruction(0) - { *n += 1;} - ]* - | /* empty replacement, but there must be a - * structure initializer anyway - */ - { fputs("\t{\"\", {",genc); - for (i = 0; i < maxoperand; i++) { - fprintf(genc, "%c{\"\",-1,\"\"}",i?',':' '); - } - fputs("}}",genc); - } - ] -; - - -identifier - { char *p = idbuf; } : - LETTER - { *p++ = dot.t_attrib;} - [ %while (1) - LETTER { *p++ = dot.t_attrib;} - | DIGIT { *p++ = dot.t_attrib;} - ]* - { *p = '\0';} -; - -separator : - '%' '%' SPACE* LINE_TERMINATOR -; +/* $Id$ */ +/* + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ +/* t o p g e n . g + * + * Grammar of optimizer description, and some code generation + */ + +%token LETTER, DIGIT, OTHER, SPACE; +%token LINE_TERMINATOR, OPERAND_SEPARATOR, INSTRUCTION_SEPARATOR, + PATTERN_SEPARATOR, OPEN_BRACKET, CLOSE_BRACKET; +%lexical LLlex; +%start LLparse, optim_description; + +{ +#include +#include +#include +#include "token.h" +#include "symtab.h" +#include "misc.h" +#include "hash.h" +#include "pattern.h" + +char idbuf[BUFSIZ], buf[BUFSIZ]; +int countid; /* # of variables */ +int countpat; /* # of patterns */ +static int patlen; /* Maximum number of instructions in pattern */ +static int maxoperand; /* Maximum number of operands of instruction */ +extern FILE *input; /* file descriptor of inputfile */ + + + +extern int onlyspace(char* s); +extern void error(char *s, char* s1); + + +} + +optim_description + { struct symtab *p; } : + SPACE* parameters + { p = findident("MAXOP",LOOKING,&deftable); + if (p == 0) maxoperand = 2; /* default */ + else maxoperand = p->s_num; + } + separator SPACE* mode_definitions + separator SPACE* patterns + separator + { register int c; + fprintf(genc, linedir, lineno, inpfile); + while ((c = getc(input)) != EOF) { + putc(c,genc); + } + } +; + +parameters : + [ parameter_line | declaration_block ]* +; + +parameter_line + { struct symtab *p; + int lin; + } : + identifier + { p = findident(idbuf,ENTERING,&deftable);} + SPACE + { lin = lineno;} + value + { p->s_num = atoi(buf);} + /* This action in fact only needed for MAXOP */ + LINE_TERMINATOR + SPACE* + { fprintf(genh, linedir, lin, inpfile); + fprintf(genh,"#define %s %s\n",p->s_name,buf);} +; + +value + { char *p1 = buf;} : + [ + [ OPEN_BRACKET + | CLOSE_BRACKET + | OPERAND_SEPARATOR + | PATTERN_SEPARATOR + | INSTRUCTION_SEPARATOR + | SPACE + | LETTER + | DIGIT + | OTHER + | '%' + ] + { *p1++ = dot.t_attrib;} + ]* + { *p1 = '\0';} +; + +declaration_block : + OPEN_BRACKET + { fprintf(genh, linedir, lineno, inpfile);} + [ + [ LINE_TERMINATOR + | OPERAND_SEPARATOR + | PATTERN_SEPARATOR + | INSTRUCTION_SEPARATOR + | SPACE + | LETTER + | DIGIT + | OTHER + | '%' + ] + { putc(dot.t_attrib, genh);} + ]* + CLOSE_BRACKET + SPACE* + { putc('\n', genh);} +; + +mode_definitions + { int lin; } : + { fputs("int tok_chk(int varno) {\n\tint r;\n", genc); + fputs("\tchar *VAL;\n\n",genc); + fputs("\tVAL = var[varno].value;\n",genc); + fputs("\tswitch(varno) {\n",genc); + } + [ + token_list + constraint(&lin) + { fprintf(genc,linedir,lin,inpfile); + fprintf(genc,"\t\tr = (%s); break;\n",buf); + } + LINE_TERMINATOR + SPACE* + ]* + { fputs("\tdefault :\n\t\tassert(0);\n",genc); + fputs("\t}\n\treturn r;\n}\n\n",genc); + } +; + +token_list : + new_identifier + SPACE* + [ + OPERAND_SEPARATOR + SPACE* + new_identifier + SPACE* + ]* +; + +new_identifier + { struct symtab *p;} : + identifier + { p = findident(idbuf,ENTERING,&idtable); + p->s_num = ++countid; + fprintf(genc,"\tcase %d:\n", countid); + } +; + +constraint (int *lin;) + { char *p = buf; } : + OPEN_BRACKET + { *lin = lineno;} + [ + [ LINE_TERMINATOR + | OPERAND_SEPARATOR + | PATTERN_SEPARATOR + | INSTRUCTION_SEPARATOR + | LETTER + | DIGIT + | SPACE + | OTHER + | '%' + ] + { *p++ = dot.t_attrib;} + ]* + { *p = '\0'; + if (onlyspace(buf)) strcpy(buf,"TRUE"); + } + CLOSE_BRACKET + SPACE* +; + +patterns + { int lin; + char *constr; + int np, nr; + } : +[ + { countpat++; + constr = (char *) 0; + fprintf(genc,"struct instr_descr pat%d[] = {\n", + countpat); + } + instruction_list(&np) + { if (np > patlen) patlen = np; + fputs("\n};\n\n",genc); + } + [ + constraint(&lin) + { /* Save the constraint, we need it later on */ + constr = malloc((unsigned)(strlen(buf)+1)); + strcpy(constr,buf); + } + ]? + PATTERN_SEPARATOR + { fprintf(genc,"struct instr_descr rep%d[] = {\n", + countpat); + } + replacement(&nr) + { fputs("\n};\n\n",genc);} + LINE_TERMINATOR + SPACE* + { addpattern(constr,lin,np,nr);} +]* + { printhashtable(); + printpatterns(); + fprintf(genh,"#define NRVARS %d\n",countid); + fprintf(genh,"#define NRPATTERNS %d\n",countpat); + fprintf(genh,"#define MIN_WINDOW_SIZE %d\n", + patlen+3); + fclose(genh); + } +; + +instruction_list(int *n;) : + instruction(1) + { *n = 1;} + [ + INSTRUCTION_SEPARATOR + { fputs(",\n",genc);} + SPACE* + instruction(0) + { *n += 1;} + ]* +; + +instruction(int opt;) + { int count = 0;} : + opcode(opt) + { if (strcmp(buf,"ANY") != 0) { + fprintf(genc,"\t{\"%s\", {",buf); + } + else fputs("\t{(char *) 0, {",genc); + count = 0; + } + [ + operand(' ') + { count = 1;} + [ + OPERAND_SEPARATOR + { count++;} + SPACE* + operand(',') + ]* + { if (count > maxoperand) { + error("Too many operands",""); + } + } + ]? + { while (count++ < maxoperand) { + fprintf(genc,"%c{\"\",-1,\"\"}",count == 1 ? ' ' : ','); + } + putc('}',genc); + putc('}',genc); + } +; + +opcode(int opt;) + { char *p = buf;} : + [ + [ LETTER + | DIGIT + | OTHER + ] + { *p++ = dot.t_attrib;} + ]+ + SPACE+ + { *p = '\0'; + if (opt) addtohashtable(buf,countpat); + } +; + +operand(int c;) + { register struct symtab *p = 0;} : + { fprintf(genc, "%c{\"", c);} + [ + identifier + { if (!p) { + p = findident(idbuf,LOOKING,&idtable); + if (p) fprintf(genc,"\",%d,\"",p->s_num); + else fputs(idbuf,genc); + } + else fputs(idbuf,genc); + } + | DIGIT + { putc(dot.t_attrib,genc);} + | OTHER + { putc(dot.t_attrib,genc);} + ]+ + { if (p) fputs("\"}",genc); + else fputs("\",0,\"\"}",genc); + } + SPACE* +; + +replacement (int *n;) + {register int i;} : + SPACE* + { *n = 0;} + [ + instruction(0) + { *n = 1;} + [ + INSTRUCTION_SEPARATOR + { fputs(",\n", genc);} + SPACE* + instruction(0) + { *n += 1;} + ]* + | /* empty replacement, but there must be a + * structure initializer anyway + */ + { fputs("\t{\"\", {",genc); + for (i = 0; i < maxoperand; i++) { + fprintf(genc, "%c{\"\",-1,\"\"}",i?',':' '); + } + fputs("}}",genc); + } + ] +; + + +identifier + { char *p = idbuf; } : + LETTER + { *p++ = dot.t_attrib;} + [ %while (1) + LETTER { *p++ = dot.t_attrib;} + | DIGIT { *p++ = dot.t_attrib;} + ]* + { *p = '\0';} +; + +separator : + '%' '%' SPACE* LINE_TERMINATOR +;