return;
}
+/*------------------------------------------------------------------
+ checkTypeSanity: prevent the user from doing e.g.:
+ unsigned float uf;
+ ------------------------------------------------------------------*/
+void checkTypeSanity(sym_link *dest) {
+ char *noun;
+ switch (SPEC_NOUN(dest))
+ {
+ case V_CHAR: noun="char"; break;
+ case V_INT: noun="int"; break;
+ case V_FLOAT: noun="float"; break;
+ case V_DOUBLE: noun="double"; break;
+ case V_VOID: noun="void"; break;
+ default: noun="unknown type"; break;
+ }
+
+ if ((SPEC_NOUN(dest)==V_CHAR ||
+ SPEC_NOUN(dest)==V_FLOAT ||
+ SPEC_NOUN(dest)==V_DOUBLE ||
+ SPEC_NOUN(dest)==V_VOID) &&
+ (SPEC_SHORT(dest) || SPEC_LONG(dest))) {
+ // long or short for char float double or void
+ werror (E_LONG_OR_SHORT_INVALID, noun, yylval.yychar);
+ }
+ if ((SPEC_NOUN(dest)==V_FLOAT ||
+ SPEC_NOUN(dest)==V_DOUBLE ||
+ SPEC_NOUN(dest)==V_VOID) &&
+ (SPEC_SIGNED(dest) || SPEC_USIGN(dest))) {
+ // signed or unsigned for float double or void
+ werror (E_SIGNED_OR_UNSIGNED_INVALID, noun, yylval.yychar);
+ }
+ if (SPEC_SIGNED(dest) && SPEC_USIGN(dest)) {
+ // signed AND unsigned
+ werror (E_SIGNED_AND_UNSIGNED_INVALID, noun, yylval.yychar);
+ }
+ if (SPEC_SHORT(dest) && SPEC_LONG(dest)) {
+ // short AND long
+ werror (E_LONG_AND_SHORT_INVALID, noun, yylval.yychar);
+ }
+}
+
/*------------------------------------------------------------------*/
-/* mergeSpec - merges two specifiers and returns the new one */
+/* mergeSpec - merges two specifiers and returns the new one */
/*------------------------------------------------------------------*/
sym_link *
mergeSpec (sym_link * dest, sym_link * src)
{
+
+ /* we shouldn't redeclare the type */
+ if (SPEC_NOUN (dest) && SPEC_NOUN (src)) {
+ werror(E_TWO_OR_MORE_DATA_TYPES, yylval.yychar);
+ }
+
/* if noun different then src overrides */
if (SPEC_NOUN (dest) != SPEC_NOUN (src) && !SPEC_NOUN (dest))
SPEC_NOUN (dest) = SPEC_NOUN (src);
SPEC_LONG (dest) |= SPEC_LONG (src);
SPEC_SHORT (dest) |= SPEC_SHORT (src);
SPEC_USIGN (dest) |= SPEC_USIGN (src);
+ SPEC_SIGNED (dest) |= SPEC_SIGNED (src);
SPEC_STAT (dest) |= SPEC_STAT (src);
SPEC_EXTR (dest) |= SPEC_EXTR (src);
SPEC_ABSA (dest) |= SPEC_ABSA (src);
if (IS_STRUCT (dest) && SPEC_STRUCT (dest) == NULL)
SPEC_STRUCT (dest) = SPEC_STRUCT (src);
+ checkTypeSanity(dest);
+
return dest;
}
}
/*------------------------------------------------------------------*/
-/* newCharLink() - creates an int type */
+/* newCharLink() - creates an char type */
/*------------------------------------------------------------------*/
sym_link *
newCharLink ()
/* noun definitions */
typedef enum
{
- V_INT = 0,
+ V_INT = 1,
V_FLOAT,
V_CHAR,
V_VOID,
V_STRUCT,
V_LABEL,
V_BIT,
- V_SBIT
+ V_SBIT,
+ V_DOUBLE
}
NOUN;
}
STORAGE_CLASS;
-#define TF_LONG 0x00000001 /* type long int */
-#define TF_SHORT 0x00000002 /* type short */
-#define TF_UNSIGNED 0x00000004 /* type is unsigned */
-#define TF_STATIC 0x00000008 /* type is static */
-#define TF_EXTERN 0x00000010 /* type is extern */
-#define TF_ABSADDR 0x00000020 /* type has absolute address */
-#define TF_REENT 0x00000040 /* type of func is reentrant func */
-#define TF_INTRRNT 0x00000080 /* is an interrupt routine */
-
/* specifier is the last in the type-chain */
typedef struct specifier
{
unsigned _long:1; /* 1=long */
unsigned _short:1; /* 1=short int */
unsigned _unsigned:1; /* 1=unsigned, 0=signed */
+ unsigned _signed:1; /* just for sanity checks only*/
unsigned _static:1; /* 1=static keyword found */
unsigned _extern:1; /* 1=extern found */
unsigned _absadr:1; /* absolute address specfied */
#define SPEC_LONG(x) x->select.s._long
#define SPEC_SHORT(x) x->select.s._short
#define SPEC_USIGN(x) x->select.s._unsigned
+#define SPEC_SIGNED(x) x->select.s._signed
#define SPEC_SCLS(x) x->select.s.sclass
#define SPEC_ENUM(x) x->select.s._isenum
#define SPEC_OCLS(x) x->select.s.oclass
" Cannot determine which register bank to save." },
{ E_NO_SUCH_BANK, ERROR_LEVEL_ERROR,
"called function uses unknown register bank %d." },
+{ E_TWO_OR_MORE_DATA_TYPES, ERROR_LEVEL_ERROR,
+ "two or more data types in declaration for '%s'" },
+{ E_LONG_OR_SHORT_INVALID, ERROR_LEVEL_ERROR,
+ "long or short specified for %s '%s'" },
+{ E_SIGNED_OR_UNSIGNED_INVALID, ERROR_LEVEL_ERROR,
+ "signed or unsigned specified for %s '%s'" },
+{ E_LONG_AND_SHORT_INVALID, ERROR_LEVEL_ERROR,
+ "both long and short specified for %s '%s'" },
+{ E_SIGNED_AND_UNSIGNED_INVALID, ERROR_LEVEL_ERROR,
+ "both signed and unsigned specified for %s '%s'" },
};
/*
-------------------------------------------------------------------------------
#define E_INVALID_HEX 138 /* \x used with no following hex digits */
#define W_FUNCPTR_IN_USING_ISR 139 /* Call via function pointer in ISR with using attribute. */
#define E_NO_SUCH_BANK 140 /* 'using' attribute specifies non-existant register bank. */
+#define E_TWO_OR_MORE_DATA_TYPES 141
+#define E_LONG_OR_SHORT_INVALID 142 /* long or short invalid for .. */
+#define E_SIGNED_OR_UNSIGNED_INVALID 143 /* signed or unsigned invalid for .. */
+#define E_LONG_AND_SHORT_INVALID 144 /* long and short invalid for .. */
+#define E_SIGNED_AND_UNSIGNED_INVALID 145 /* signed and unsigned invalid for .. */
/** Describes the maximum error level that will be logged. Any level
* includes all of the levels listed after it.