#include <errno.h>
#include <ctype.h>
+#include "../common/xmalloc.h"
+
#include "anonname.h"
#include "codegen.h"
#include "datatype.h"
#include "function.h"
#include "global.h"
#include "litpool.h"
-#include "mem.h"
#include "pragma.h"
#include "scanner.h"
#include "symtab.h"
static void optional_modifiers (void)
/* Eat optional "const" or "volatile" tokens */
{
- while (curtok == CONST || curtok == VOLATILE) {
+ while (curtok == TOK_CONST || curtok == TOK_VOLATILE) {
/* Skip it */
- gettok ();
+ NextToken ();
}
}
static void optionalint (void)
/* Eat an optional "int" token */
{
- if (curtok == INT) {
+ if (curtok == TOK_INT) {
/* Skip it */
- gettok ();
+ NextToken ();
}
}
static void optionalsigned (void)
/* Eat an optional "signed" token */
{
- if (curtok == SIGNED) {
+ if (curtok == TOK_SIGNED) {
/* Skip it */
- gettok ();
+ NextToken ();
}
}
/* Check the storage class given */
switch (curtok) {
- case EXTERN:
+ case TOK_EXTERN:
D->StorageClass = SC_EXTERN | SC_STATIC;
- gettok ();
+ NextToken ();
break;
- case STATIC:
+ case TOK_STATIC:
D->StorageClass = SC_STATIC;
- gettok ();
+ NextToken ();
break;
- case REGISTER:
+ case TOK_REGISTER:
D->StorageClass = SC_REGISTER | SC_STATIC;
- gettok ();
+ NextToken ();
break;
- case AUTO:
+ case TOK_AUTO:
D->StorageClass = SC_AUTO;
- gettok ();
+ NextToken ();
break;
- case TYPEDEF:
+ case TOK_TYPEDEF:
D->StorageClass = SC_TYPEDEF;
- gettok ();
+ NextToken ();
break;
default:
ident Ident;
/* Accept forward definitions */
- if (curtok != LCURLY) {
+ if (curtok != TOK_LCURLY) {
return;
}
/* Skip the opening curly brace */
- gettok ();
+ NextToken ();
/* Read the enum tags */
EnumVal = 0;
- while (curtok != RCURLY) {
+ while (curtok != TOK_RCURLY) {
/* We expect an identifier */
- if (curtok != IDENT) {
+ if (curtok != TOK_IDENT) {
Error (ERR_IDENT_EXPECTED);
continue;
}
/* Remember the identifier and skip it */
strcpy (Ident, CurTok.Ident);
- gettok ();
+ NextToken ();
/* Check for an assigned value */
- if (curtok == ASGN) {
+ if (curtok == TOK_ASSIGN) {
struct expent lval;
- gettok ();
+ NextToken ();
constexpr (&lval);
EnumVal = lval.e_const;
}
AddEnumSym (Ident, EnumVal++);
/* Check for end of definition */
- if (curtok != COMMA)
+ if (curtok != TOK_COMMA)
break;
- gettok ();
+ NextToken ();
}
ConsumeRCurly ();
}
SymEntry* Entry;
- if (curtok != LCURLY) {
+ if (curtok != TOK_LCURLY) {
/* Just a forward declaration. Try to find a struct with the given
* name. If there is none, insert a forward declaration into the
* current lexical level.
*/
- Entry = FindStructSym (Name);
- if (Entry == 0 || Entry->Flags != SC_STRUCT) {
+ Entry = FindTagSym (Name);
+ if (Entry == 0) {
Entry = AddStructSym (Name, 0, 0);
+ } else if (SymIsLocal (Entry) && (Entry->Flags & SC_STRUCT) == 0) {
+ /* Already defined in the level but no struct */
+ Error (ERR_SYMBOL_KIND);
}
- return Entry;
+ return Entry;
}
/* Add a forward declaration for the struct in the current lexical level */
Entry = AddStructSym (Name, 0, 0);
/* Skip the curly brace */
- gettok ();
+ NextToken ();
/* Enter a new lexical level for the struct */
EnterStructLevel ();
/* Parse struct fields */
Size = 0;
- while (curtok != RCURLY) {
+ while (curtok != TOK_RCURLY) {
/* Get the type of the entry */
DeclSpec Spec;
}
}
- if (curtok != COMMA)
+ if (curtok != TOK_COMMA)
break;
- gettok ();
+ NextToken ();
}
ConsumeSemi ();
}
/* Skip the closing brace */
- gettok ();
+ NextToken ();
/* Remember the symbol table and leave the struct level */
FieldTab = GetSymTab ();
static void ParseTypeSpec (DeclSpec* D, int Default)
/* Parse a type specificier */
{
- ident Ident;
- SymEntry* Entry;
- type StructType;
+ ident Ident;
+ SymEntry* Entry;
+ type StructType;
- /* Assume have an explicit type */
+ /* Assume we have an explicit type */
D->Flags &= ~DS_DEF_TYPE;
/* Skip const or volatile modifiers if needed */
/* Look at the data type */
switch (curtok) {
- case VOID:
- gettok ();
+ case TOK_VOID:
+ NextToken ();
D->Type[0] = T_VOID;
D->Type[1] = T_END;
break;
- case CHAR:
- gettok ();
+ case TOK_CHAR:
+ NextToken ();
D->Type[0] = GetDefaultChar();
D->Type[1] = T_END;
break;
- case LONG:
- gettok ();
- if (curtok == UNSIGNED) {
- gettok ();
+ case TOK_LONG:
+ NextToken ();
+ if (curtok == TOK_UNSIGNED) {
+ NextToken ();
optionalint ();
D->Type[0] = T_ULONG;
D->Type[1] = T_END;
}
break;
- case SHORT:
- gettok ();
- if (curtok == UNSIGNED) {
- gettok ();
+ case TOK_SHORT:
+ NextToken ();
+ if (curtok == TOK_UNSIGNED) {
+ NextToken ();
optionalint ();
D->Type[0] = T_USHORT;
D->Type[1] = T_END;
}
break;
- case INT:
- gettok ();
+ case TOK_INT:
+ NextToken ();
D->Type[0] = T_INT;
D->Type[1] = T_END;
break;
- case SIGNED:
- gettok ();
+ case TOK_SIGNED:
+ NextToken ();
switch (curtok) {
- case CHAR:
- gettok ();
+ case TOK_CHAR:
+ NextToken ();
D->Type[0] = T_CHAR;
D->Type[1] = T_END;
break;
- case SHORT:
- gettok ();
+ case TOK_SHORT:
+ NextToken ();
optionalint ();
D->Type[0] = T_SHORT;
D->Type[1] = T_END;
break;
- case LONG:
- gettok ();
+ case TOK_LONG:
+ NextToken ();
optionalint ();
D->Type[0] = T_LONG;
D->Type[1] = T_END;
break;
- case INT:
- gettok ();
+ case TOK_INT:
+ NextToken ();
/* FALL THROUGH */
default:
}
break;
- case UNSIGNED:
- gettok ();
+ case TOK_UNSIGNED:
+ NextToken ();
switch (curtok) {
- case CHAR:
- gettok ();
+ case TOK_CHAR:
+ NextToken ();
D->Type[0] = T_UCHAR;
D->Type[1] = T_END;
- break;
+ break;
- case SHORT:
- gettok ();
+ case TOK_SHORT:
+ NextToken ();
optionalint ();
D->Type[0] = T_USHORT;
D->Type[1] = T_END;
break;
- case LONG:
- gettok ();
+ case TOK_LONG:
+ NextToken ();
optionalint ();
D->Type[0] = T_ULONG;
D->Type[1] = T_END;
break;
- case INT:
- gettok ();
+ case TOK_INT:
+ NextToken ();
/* FALL THROUGH */
default:
}
break;
- case STRUCT:
- case UNION:
- StructType = (curtok == STRUCT)? T_STRUCT : T_UNION;
- gettok ();
- if (curtok == IDENT) {
+ case TOK_STRUCT:
+ case TOK_UNION:
+ StructType = (curtok == TOK_STRUCT)? T_STRUCT : T_UNION;
+ NextToken ();
+ /* */
+ if (curtok == TOK_IDENT) {
strcpy (Ident, CurTok.Ident);
- gettok ();
+ NextToken ();
} else {
AnonName (Ident, (StructType == T_STRUCT)? "struct" : "union");
}
+ /* Remember we have an extra type decl */
+ D->Flags |= DS_EXTRA_TYPE;
/* Declare the struct in the current scope */
Entry = ParseStructDecl (Ident, StructType);
/* Encode the struct entry into the type */
D->Type[DECODE_SIZE+1] = T_END;
break;
- case ENUM:
- gettok ();
- if (curtok != LCURLY) {
- /* Named enum */
- Consume (IDENT, ERR_IDENT_EXPECTED);
+ case TOK_ENUM:
+ NextToken ();
+ if (curtok != TOK_LCURLY) {
+ /* Named enum */
+ if (curtok == TOK_IDENT) {
+ /* Find an entry with this name */
+ Entry = FindTagSym (CurTok.Ident);
+ if (Entry) {
+ if (SymIsLocal (Entry) && (Entry->Flags & SC_ENUM) == 0) {
+ Error (ERR_SYMBOL_KIND);
+ }
+ } else {
+ /* Insert entry into table ### */
+ }
+ /* Skip the identifier */
+ NextToken ();
+ } else {
+ Error (ERR_IDENT_EXPECTED);
+ }
}
+ /* Remember we have an extra type decl */
+ D->Flags |= DS_EXTRA_TYPE;
+ /* Parse the enum decl */
ParseEnumDecl ();
D->Type[0] = T_INT;
D->Type[1] = T_END;
break;
- case IDENT:
+ case TOK_IDENT:
Entry = FindSym (CurTok.Ident);
if (Entry && IsTypeDef (Entry)) {
/* It's a typedef */
- gettok ();
+ NextToken ();
TypeCpy (D->Type, Entry->Type);
break;
}
-static FuncDesc* ParseFuncDecl (void)
-/* Parse the argument list of a function. */
+static type* ParamTypeCvt (type* T)
+/* If T is an array, convert it to a pointer else do nothing. Return the
+ * resulting type.
+ */
{
- unsigned UnnamedCount = 0;
- unsigned Offs;
- SymEntry* Sym;
- type* Type;
+ if (IsArray (T)) {
+ T += DECODE_SIZE;
+ T[0] = T_PTR;
+ }
+ return T;
+}
- /* Create a new function descriptor */
- FuncDesc* F = NewFuncDesc ();
- /* Enter a new lexical level */
- EnterFunctionLevel ();
- /* Check for an empty or void parameter list */
- if (curtok == RPAREN) {
- /* Parameter list is empty */
- F->Flags |= (FD_EMPTY | FD_ELLIPSIS);
- } else if (curtok == VOID && nxttok == RPAREN) {
- /* Parameter list declared as void */
- gettok ();
- F->Flags |= FD_VOID_PARAM;
+static void ParseOldStyleParamList (FuncDesc* F)
+/* Parse an old style (K&R) parameter list */
+{
+ /* Parse params */
+ while (curtok != TOK_RPAREN) {
+
+ /* List of identifiers expected */
+ if (curtok != TOK_IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ }
+
+ /* Create a symbol table entry with type int */
+ AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF, 0);
+
+ /* Count arguments */
+ ++F->ParamCount;
+
+ /* Skip the identifier */
+ NextToken ();
+
+ /* Check for more parameters */
+ if (curtok == TOK_COMMA) {
+ NextToken ();
+ } else {
+ break;
+ }
}
+ /* Skip right paren. We must explicitly check for one here, since some of
+ * the breaks above bail out without checking.
+ */
+ ConsumeRParen ();
+
+ /* An optional list of type specifications follows */
+ while (curtok != TOK_LCURLY) {
+
+ DeclSpec Spec;
+
+ /* Read the declaration specifier */
+ ParseDeclSpec (&Spec, SC_AUTO, T_INT);
+
+ /* We accept only auto and register as storage class specifiers, but
+ * we ignore all this, since we use auto anyway.
+ */
+ if ((Spec.StorageClass & SC_AUTO) == 0 &&
+ (Spec.StorageClass & SC_REGISTER) == 0) {
+ Error (ERR_ILLEGAL_STORAGE_CLASS);
+ }
+
+ /* Parse a comma separated variable list */
+ while (1) {
+
+ Declaration Decl;
+
+ /* Read the parameter */
+ ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
+ if (Decl.Ident[0] != '\0') {
+
+ /* We have a name given. Search for the symbol */
+ SymEntry* Sym = FindLocalSym (Decl.Ident);
+ if (Sym) {
+ /* Found it, change the default type to the one given */
+ ChangeSymType (Sym, ParamTypeCvt (Decl.Type));
+ } else {
+ Error (ERR_UNKNOWN_IDENT, Decl.Ident);
+ }
+ }
+
+ if (curtok == TOK_COMMA) {
+ NextToken ();
+ } else {
+ break;
+ }
+
+ }
+
+ /* Variable list must be semicolon terminated */
+ ConsumeSemi ();
+ }
+}
+
+
+
+static void ParseAnsiParamList (FuncDesc* F)
+/* Parse a new style (ANSI) parameter list */
+{
/* Parse params */
- while (curtok != RPAREN) {
+ while (curtok != TOK_RPAREN) {
+
+ DeclSpec Spec;
+ Declaration Decl;
- DeclSpec Spec;
- Declaration Decl;
/* Allow an ellipsis as last parameter */
- if (curtok == ELLIPSIS) {
- gettok ();
+ if (curtok == TOK_ELLIPSIS) {
+ NextToken ();
F->Flags |= FD_ELLIPSIS;
break;
}
/* Unnamed symbol. Generate a name that is not user accessible,
* then handle the symbol normal.
*/
- AnonName (Decl.Ident, "param");
- ++UnnamedCount;
+ AnonName (Decl.Ident, "param");
+ F->Flags |= FD_UNNAMED_PARAMS;
- /* Clear defined bit on nonames */
- Spec.StorageClass &= ~SC_DEF;
- }
-
- /* If the parameter is an array, convert it to a pointer */
- Type = Decl.Type;
- if (IsArray (Type)) {
- Type += DECODE_SIZE;
- Type[0] = T_PTR;
- }
+ /* Clear defined bit on nonames */
+ Spec.StorageClass &= ~SC_DEF;
+ }
/* Create a symbol table entry */
- AddLocalSym (Decl.Ident, Type, Spec.StorageClass, 0);
+ AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Spec.StorageClass, 0);
/* Count arguments */
++F->ParamCount;
- F->ParamSize += SizeOf (Type);
/* Check for more parameters */
- if (curtok == COMMA) {
- gettok ();
+ if (curtok == TOK_COMMA) {
+ NextToken ();
} else {
break;
}
*/
ConsumeRParen ();
+ /* Check if this is a function definition */
+ if (curtok == TOK_LCURLY) {
+ /* Print an error if in strict ANSI mode and we have unnamed
+ * parameters.
+ */
+ if (ANSI && (F->Flags & FD_UNNAMED_PARAMS) != 0) {
+ Error (ERR_MISSING_PARAM_NAME);
+ }
+ }
+}
+
+
+
+static FuncDesc* ParseFuncDecl (void)
+/* Parse the argument list of a function. */
+{
+ unsigned Offs;
+ SymEntry* Sym;
+
+ /* Create a new function descriptor */
+ FuncDesc* F = NewFuncDesc ();
+
+ /* Enter a new lexical level */
+ EnterFunctionLevel ();
+
+ /* Check for several special parameter lists */
+ if (curtok == TOK_RPAREN) {
+ /* Parameter list is empty */
+ F->Flags |= (FD_EMPTY | FD_ELLIPSIS);
+ } else if (curtok == TOK_VOID && nxttok == TOK_RPAREN) {
+ /* Parameter list declared as void */
+ NextToken ();
+ F->Flags |= FD_VOID_PARAM;
+ } else if (curtok == TOK_IDENT && (nxttok == TOK_COMMA || nxttok == TOK_RPAREN)) {
+ /* Old style (K&R) function. Assume variable param list. */
+ F->Flags |= (FD_OLDSTYLE | FD_ELLIPSIS);
+ }
+
+ /* Parse params */
+ if ((F->Flags & FD_OLDSTYLE) == 0) {
+ /* New style function */
+ ParseAnsiParamList (F);
+ } else {
+ /* Old style function */
+ ParseOldStyleParamList (F);
+ }
+
/* Assign offsets. If the function has a variable parameter list,
* there's one additional byte (the arg size).
*/
Offs = (F->Flags & FD_ELLIPSIS)? 1 : 0;
Sym = GetSymTab()->SymTail;
while (Sym) {
+ unsigned Size = SizeOf (Sym->Type);
Sym->V.Offs = Offs;
- Offs += SizeOf (Sym->Type);
- Sym = Sym->PrevSym;
- }
-
- /* Check if this is a function definition */
- if (curtok == LCURLY) {
- /* Print an error if in strict ANSI mode and we have unnamed
- * parameters.
- */
- if (ANSI && UnnamedCount > 0) {
- Error (ERR_MISSING_PARAM_NAME);
- }
+ Offs += Size;
+ F->ParamSize += Size;
+ Sym = Sym->PrevSym;
}
/* Leave the lexical level remembering the symbol tables */
static void Decl (Declaration* D, unsigned Mode)
/* Recursively process declarators. Build a type array in reverse order. */
{
- if (curtok == STAR) {
- gettok ();
+ if (curtok == TOK_STAR) {
+ NextToken ();
/* Allow optional const or volatile modifiers */
optional_modifiers ();
Decl (D, Mode);
*D->T++ = T_PTR;
return;
- } else if (curtok == LPAREN) {
- gettok ();
+ } else if (curtok == TOK_LPAREN) {
+ NextToken ();
Decl (D, Mode);
ConsumeRParen ();
- } else if (curtok == FASTCALL) {
+ } else if (curtok == TOK_FASTCALL) {
/* Remember the current type pointer */
type* T = D->T;
/* Skip the fastcall token */
- gettok ();
+ NextToken ();
/* Parse the function */
Decl (D, Mode);
/* Set the fastcall flag */
}
return;
} else {
- /* Things depend on Mode now:
+ /* Things depend on Mode now:
* - Mode == DM_NEED_IDENT means:
- * we *must* have a type and a variable identifer.
- * - Mode == DM_NO_IDENT means:
- * we must have a type but no variable identifer
- * (if there is one, it's not read).
- * - Mode == DM_ACCEPT_IDENT means:
- * we *may* have an identifier. If there is an identifier,
- * it is read, but it is no error, if there is none.
- */
- if (Mode == DM_NO_IDENT) {
- D->Ident[0] = '\0';
- } else if (curtok == IDENT) {
+ * we *must* have a type and a variable identifer.
+ * - Mode == DM_NO_IDENT means:
+ * we must have a type but no variable identifer
+ * (if there is one, it's not read).
+ * - Mode == DM_ACCEPT_IDENT means:
+ * we *may* have an identifier. If there is an identifier,
+ * it is read, but it is no error, if there is none.
+ */
+ if (Mode == DM_NO_IDENT) {
+ D->Ident[0] = '\0';
+ } else if (curtok == TOK_IDENT) {
strcpy (D->Ident, CurTok.Ident);
- gettok ();
- } else {
- if (Mode == DM_NEED_IDENT) {
- Error (ERR_IDENT_EXPECTED);
- }
- D->Ident[0] = '\0';
- return;
- }
+ NextToken ();
+ } else {
+ if (Mode == DM_NEED_IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ }
+ D->Ident[0] = '\0';
+ return;
+ }
}
- while (curtok == LBRACK || curtok == LPAREN) {
- if (curtok == LPAREN) {
+ while (curtok == TOK_LBRACK || curtok == TOK_LPAREN) {
+ if (curtok == TOK_LPAREN) {
/* Function declaration */
FuncDesc* F;
- gettok ();
+ NextToken ();
/* Parse the function declaration */
F = ParseFuncDecl ();
*D->T++ = T_FUNC;
} else {
/* Array declaration */
unsigned long Size = 0;
- gettok ();
+ NextToken ();
/* Read the size if it is given */
- if (curtok != RBRACK) {
+ if (curtok != TOK_RBRACK) {
struct expent lval;
constexpr (&lval);
Size = lval.e_const;
+void CheckEmptyDecl (const DeclSpec* D)
+/* Called after an empty type declaration (that is, a type declaration without
+ * a variable). Checks if the declaration does really make sense and issues a
+ * warning if not.
+ */
+{
+ if ((D->Flags & DS_EXTRA_TYPE) == 0) {
+ Warning (WARN_USELESS_DECL);
+ }
+}
+
+
+
static void ParseVoidInit (void)
/* Parse an initialization of a void variable (special cc65 extension) */
{
case T_PTR:
case T_ARRAY:
if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
- /* Make it word sized */
+ /* Make it word sized */
lval.e_const &= 0xFFFF;
}
DefineData (&lval);
}
- if (curtok != COMMA) {
+ if (curtok != TOK_COMMA) {
break;
}
- gettok ();
+ NextToken ();
- } while (curtok != RCURLY);
+ } while (curtok != TOK_RCURLY);
ConsumeRCurly ();
}
/* Get a pointer to the list of symbols */
Entry = Tab->SymHead;
- while (curtok != RCURLY) {
- if (Entry == NULL) {
+ while (curtok != TOK_RCURLY) {
+ if (Entry == 0) {
Error (ERR_TOO_MANY_INITIALIZERS);
return;
}
ParseInit (Entry->Type);
Entry = Entry->NextSym;
- if (curtok != COMMA)
+ if (curtok != TOK_COMMA)
break;
- gettok ();
+ NextToken ();
}
/* Consume the closing curly brace */
case T_ARRAY:
sz = Decode (tptr + 1);
t = tptr + DECODE_SIZE + 1;
- if ((t [0] == T_CHAR || t [0] == T_UCHAR) && curtok == SCONST) {
+ if ((t [0] == T_CHAR || t [0] == T_UCHAR) && curtok == TOK_SCONST) {
str = GetLiteral (curval);
count = strlen (str) + 1;
TranslateLiteralPool (curval); /* Translate into target charset */
g_defbytes (str, count);
ResetLiteralOffs (curval); /* Remove string from pool */
- gettok ();
+ NextToken ();
} else {
ConsumeLCurly ();
count = 0;
- while (curtok != RCURLY) {
+ while (curtok != TOK_RCURLY) {
ParseInit (tptr + DECODE_SIZE + 1);
++count;
- if (curtok != COMMA)
+ if (curtok != TOK_COMMA)
break;
- gettok ();
+ NextToken ();
}
ConsumeRCurly ();
}