+#ifndef lint
+static char RCSid[] = "$Header: constantcode.c,v 2.0 85/11/21 07:21:32 jqj Exp $";
+#endif
+
+/* $Log: constantcode.c,v $
+ * Revision 2.0 85/11/21 07:21:32 jqj
+ * 4.3BSD standard release
+ *
+ * Revision 1.4 85/05/23 06:19:32 jqj
+ * *** empty log message ***
+ *
+ * Revision 1.4 85/05/23 06:19:32 jqj
+ * Public Beta-test version, released 24 May 1985
+ *
+ * Revision 1.3 85/03/26 06:09:41 jqj
+ * Revised public alpha-test version, released 26 March 1985
+ *
+ * Revision 1.2 85/03/11 16:38:56 jqj
+ * Public alpha-test version, released 11 March 1985
+ *
+ * Revision 1.1 85/02/15 13:55:18 jqj
+ * Initial revision
+ *
+ */
+
+/*
+ * Generate code for constant declarations.
+ */
+
+#include "compiler.h"
+
+/*
+ * Generate code for constant declarations
+ */
+define_constant(name, typtr, value)
+ struct object *name;
+ struct type *typtr;
+ struct constant *value;
+{
+ char *fullname;
+
+ name->o_class = O_CONSTANT;
+ name->o_constant = value;
+ fullname = make_full_name( name->o_module,
+ name->o_modversion, name_of(name));
+ /*
+ * Check for simple case of Foo: TypeBaz = Mumble;
+ * where Mumble is another constant. In this case,
+ * just use the existing declaration
+ */
+ if (value->cn_name != NULL) {
+ if (!recursive_flag) {
+ fprintf(header,"#define %s %s\n",
+ fullname, value->cn_name);
+ /* open scope */
+ fprintf(header1,"#define %s %s\n",
+ name_of(name), value->cn_name);
+ }
+ return;
+ }
+ /*
+ * We have to generate some code for this one. We'll generate
+ * the declaration in the header file of a static variable
+ * initialized to the appropriate values.
+ */
+ value->cn_name = fullname;
+ if (recursive_flag)
+ return; /* it's already been expanded elsewhere */
+ /* open scope */
+ fprintf(header1,"#define %s %s\n", name_of(name), fullname);
+ /* make sure the type is defined */
+ if (typename(typtr) == NULL) {
+ /* create an anonymous (not in symboltable) type and subtypes */
+ char * typenam;
+ typenam = gensym("T_cn");
+ code_type(typenam, typtr);
+ typename(typtr) = typenam;
+ }
+ /* depending on the type, generate appropriate initializer */
+ switch (typtr->type_constr) {
+ case C_PROCEDURE:
+ define_procedure_constant(name, typtr, value);
+ break;
+ case C_ERROR:
+ define_error_constant(name, typtr, value);
+ break;
+ case C_NUMERIC:
+ case C_BOOLEAN:
+ case C_STRING:
+ case C_ENUMERATION:
+ /* these are simple, since they can't include sequences */
+ fprintf(header, "\nstatic %s %s = {%s};\n",
+ typename(typtr), value->cn_name, value->cn_value);
+ break;
+ default:
+ /* the general case */
+ scan_for_sequences(typtr, value); /* kludge */
+ fprintf(header, "\nstatic %s %s = ",
+ typename(typtr), value->cn_name);
+ code_constant(typtr, value);
+ fprintf(header,";\n");
+ break;
+ }
+ return;
+}
+
+
+/*
+ * Generate client and server code for error constants
+ */
+define_error_constant(symbol,typtr,value)
+ struct object *symbol;
+ struct type *typtr;
+ struct constant *value;
+{
+ char *errvalue;
+
+ if (recursive_flag)
+ return; /* can't happen */
+ if (typtr->type_constr != C_ERROR)
+ error(FATAL, "internal error (define_error_constant): not an error");
+ if (value->cn_constr != C_NUMERIC) {
+ error(ERROR,"Values of ERRORs must be numeric");
+ errvalue = "-1";
+ }
+ else
+ errvalue = value->cn_value;
+ fprintf(header,"\n#define %s (ERROR_OFFSET+%s)\n\
+#define %sArgs %s\n",
+ value->cn_name, errvalue,
+ value->cn_name, typename(typtr));
+ fprintf(header1,"#define %sArgs %sArgs\n",
+ symbol->o_name, value->cn_name);
+ value->cn_constr = C_ERROR;
+ /* put this error in the constant's data structure */
+ /* also store this error on the global list */
+ if (typtr->type_list == NIL) {
+ value->cn_list = cons((list) errvalue, NIL);
+ Errors = cons( cons((list) value, NIL), Errors);
+ }
+ else {
+ value->cn_list = cons((list) errvalue, (list) typtr);
+ Errors = cons( cons((list) value, (list) typtr), Errors);
+ }
+}
+
+/*
+ * recursively generate the code for a constant
+ */
+code_constant(typtr, value)
+ struct type *typtr;
+ struct constant *value;
+{
+ switch (typtr->type_constr) {
+ case C_NUMERIC:
+ case C_BOOLEAN:
+ case C_STRING:
+ case C_ENUMERATION:
+ if (value == (struct constant*) 0)
+ fprintf(header, "0");
+ else
+ fprintf(header, "%s", value->cn_value);
+ break;
+ case C_ARRAY:
+ code_array_constant(typtr,value);
+ break;
+ case C_SEQUENCE:
+ code_sequence_constant(typtr,value);
+ break;
+ case C_RECORD:
+ code_record_constant(typtr,value);
+ break;
+ case C_CHOICE:
+ code_choice_constant(typtr,value);
+ break;
+ case C_ERROR:
+ error(ERROR,"Error constants may not be part of a structure");
+ break;
+ case C_PROCEDURE:
+ error(ERROR,"Procedures may not be part of a structure");
+ }
+}
+
+/*
+ * Given the name of a record field and a record constant, return
+ * the corresponding component of the record constant.
+ */
+static struct constant *
+findcomponent(name,recvalue)
+ char *name;
+ struct constant *recvalue;
+{
+ list p;
+
+ if (recvalue->cn_constr != C_RECORD)
+ error(FATAL,"internal error (findcomponent): constant is of type %d",
+ recvalue->cn_constr);
+ for (p = recvalue->cn_list; p != NIL; p = cdr(p))
+ if (streq((char *) caar(p), name))
+ return((struct constant *) cdar(p));
+ return((struct constant *) 0);
+}
+
+\f
+/*
+ * kludge since PCC doesn't like initializations of the form
+ * struct {int length; Seqtype *sequence} seq = {3,{1,2,3}};
+ * instead, use:
+ * Seqtype anonymous[3] = {1,2,3};
+ * struct {int length; Seqtype *sequence} seq = {3,anonymous};
+ * We have to generate the sequence value before we walk the constant.
+ */
+scan_for_sequences(typtr, value)
+ struct type *typtr;
+ struct constant *value;
+{
+ list p;
+
+ switch (typtr->type_constr) {
+ case C_ARRAY:
+ for (p = value->cn_list; p != NIL; p = cdr(p))
+ scan_for_sequences(typtr->type_basetype,
+ (struct constant *) car(p));
+ break;
+ case C_RECORD:
+ scan_record_for_sequences(typtr, value);
+ break;
+ case C_CHOICE:
+ scan_choice_for_sequences(typtr, value);
+ break;
+ case C_SEQUENCE:
+ for (p = value->cn_list; p != NIL; p = cdr(p))
+ scan_for_sequences(typtr->type_basetype,
+ (struct constant *) car(p));
+ value->cn_seqvalname = gensym("S_v");
+ fprintf(header,"\nstatic %s %s[%d] = {\n\t",
+ typename(typtr->type_basetype), value->cn_seqvalname,
+ length(value->cn_list));
+ for (p = value->cn_list ; p != NIL ; p = cdr(p)) {
+ code_constant(typtr->type_basetype,
+ (struct constant *) car(p));
+ if (cdr(p) != NIL)
+ fprintf(header,",\n\t");
+ }
+ fprintf(header,"\n};\n");
+ break;
+ default: /* other types don't have embedded sequences */
+ break;
+ }
+}
+
+scan_record_for_sequences(typtr, value)
+ struct type *typtr;
+ struct constant *value;
+{
+ list p, q;
+ struct constant *component;
+
+ for (p = typtr->type_list; p != NIL; p = cdr(p)) {
+ q = car(p);
+ component = findcomponent((char *) caar(q),value);
+ if (component != (struct constant *) 0)
+ scan_for_sequences((struct type *) cdr(q), component);
+ }
+}
+
+/*ARGSUSED*/
+scan_choice_for_sequences(typtr, value)
+ struct type *typtr;
+ struct constant *value;
+{
+ /* constants of type CHOICE are not implemented */
+}
+
+\f
+code_array_constant(typtr, value)
+ struct type *typtr;
+ struct constant *value;
+{
+ list p;
+ int i;
+
+ if (value == (struct constant *) 0) {
+ fprintf(header,"{0");
+ for (i = 1; i < typtr->type_size; i++)
+ fprintf(header,",0");
+ fprintf(header,"}");
+ return;
+ }
+ if (typtr->type_size != length(value->cn_list))
+ error(WARNING,"wrong number of constant elements specified for array");
+ fprintf(header,"\n\t{");
+ for (p = value->cn_list; p != NIL; p = cdr(p)) {
+ code_constant(typtr->type_basetype,(struct constant *) car(p));
+ if (cdr(p) != NIL)
+ fprintf(header,",");
+ }
+ fprintf(header,"}");
+}
+
+code_choice_constant(typtr, value)
+ struct type *typtr;
+ struct constant *value;
+{
+ list p,q;
+ struct type *bt;
+ char *desigval;
+ struct object *name;
+
+ if (value == (struct constant *)0)
+ desigval = "?"; /* caar(typtr->type_designator->type_list); */
+ else
+ desigval = (char *) car(value->cn_list);
+ fprintf(header,"\n\t{ %s", desigval);
+ /* find the corresponding arm of the choice */
+ bt = TNIL;
+ for (p = typtr->type_candidates; bt==TNIL && p!=NIL; p = cdr(p)) {
+ for (q = caar(p); bt==TNIL && q!=NIL; q = cdr(q)) {
+ name = (struct object *) caar(q);
+ if (streq(name->o_enum->en_name,desigval))
+ bt = (struct type *) cdar(p);
+ }
+ }
+ if (bt == TNIL)
+ error(WARNING,"CHOICE designator %s is invalid here",desigval);
+ else if (bt != NilRecord_type)
+ error(WARNING,"Constants of type CHOICE are not supported");
+
+ fprintf(header,"\n\t}");
+}
+
+code_sequence_constant(typtr, value)
+ struct type *typtr;
+ struct constant *value;
+{
+ list p;
+ int l;
+
+ if (value == (struct constant *)0 ||
+ (p = value->cn_list) == NIL) {
+ fprintf(header,"{0, 0}");
+ return;
+ }
+ l = length(p);
+ if (typtr->type_size < l)
+ error(WARNING,"too many constant elements specified for sequence");
+ fprintf(header,"{%d, %s}",l,value->cn_seqvalname);
+}
+
+code_record_constant(typtr, value)
+ struct type *typtr;
+ struct constant *value;
+{
+ list p, q;
+ struct constant *component;
+
+ fprintf(header,"{");
+ for (p = typtr->type_list; p != NIL; p = cdr(p)) {
+ q = car(p);
+ if (value == (struct constant *) 0)
+ component = value;
+ else
+ component = findcomponent((char *) caar(q), value);
+ code_constant((struct type *) cdr(q), component);
+ if (cdr(p) != NIL)
+ fprintf(header,",");
+ }
+ fprintf(header,"\n\t}");
+}
+