4 * Ullrich von Bassewitz, 07.06.1998
30 /*****************************************************************************/
32 /*****************************************************************************/
36 Token CurTok; /* The current token */
37 Token NextTok; /* The next token */
42 #define TT_C 0 /* ANSI C token */
43 #define TT_EXT 1 /* cc65 extension */
46 static struct Keyword {
47 char* Key; /* Keyword name */
48 unsigned char Tok; /* The token */
49 unsigned char Type; /* Token type */
51 { "__AX__", AX, TT_C },
52 { "__EAX__", EAX, TT_C },
53 { "__asm__", ASM, TT_C },
54 { "__fastcall__", FASTCALL, TT_C },
55 { "asm", ASM, TT_EXT },
56 { "auto", AUTO, TT_C },
57 { "break", BREAK, TT_C },
58 { "case", CASE, TT_C },
59 { "char", CHAR, TT_C },
60 { "const", CONST, TT_C },
61 { "continue", CONTINUE, TT_C },
62 { "default", DEFAULT, TT_C },
64 { "double", DOUBLE, TT_C },
65 { "else", ELSE, TT_C },
66 { "enum", ENUM, TT_C },
67 { "extern", EXTERN, TT_C },
68 { "fastcall", FASTCALL, TT_EXT },
69 { "float", FLOAT, TT_C },
71 { "goto", GOTO, TT_C },
74 { "long", LONG, TT_C },
75 { "register", REGISTER, TT_C },
76 { "return", RETURN, TT_C },
77 { "short", SHORT, TT_C },
78 { "signed", SIGNED, TT_C },
79 { "sizeof", SIZEOF, TT_C },
80 { "static", STATIC, TT_C },
81 { "struct", STRUCT, TT_C },
82 { "switch", SWITCH, TT_C },
83 { "typedef", TYPEDEF, TT_C },
84 { "union", UNION, TT_C },
85 { "unsigned", UNSIGNED, TT_C },
86 { "void", VOID, TT_C },
87 { "volatile", VOLATILE, TT_C },
88 { "while", WHILE, TT_C },
90 #define KEY_COUNT (sizeof (Keywords) / sizeof (Keywords [0]))
94 /* Stuff for determining the type of an integer constant */
102 /*****************************************************************************/
104 /*****************************************************************************/
108 static int CmpKey (const void* Key, const void* Elem)
109 /* Compare function for bsearch */
111 return strcmp ((const char*) Key, ((const struct Keyword*) Elem)->Key);
116 static int FindKey (char* Key)
117 /* Find a keyword and return the token. Return IDENT if the token is not a
122 K = bsearch (Key, Keywords, KEY_COUNT, sizeof (Keywords [0]), CmpKey);
123 if (K && (K->Type != TT_EXT || ANSI == 0)) {
132 static int skipwhite (void)
133 /* Skip white space in the input stream, reading and preprocessing new lines
134 * if necessary. Return 0 if end of file is reached, return 1 otherwise.
139 if (readline () == 0) {
144 if (*lptr == ' ' || *lptr == '\r') {
154 void symname (char *s)
155 /* Get symbol from input stream */
159 if (k != MAX_IDENTLEN) {
164 } while (IsIdent (*lptr) || isdigit (*lptr));
171 /* Get symbol from input stream or return 0 if not a symbol. */
173 if (IsIdent (*lptr)) {
183 static void unknown (unsigned char c)
184 /* Error message for unknown character */
186 Error (ERR_INVALID_CHAR, c);
192 static unsigned hexval (int c)
193 /* Convert a hex digit into a value */
196 Error (ERR_ILLEGAL_HEX_DIGIT);
201 return toupper (c) - 'A' + 10;
207 static void SetTok (int tok)
208 /* set nxttok and bump line ptr */
216 static int SignExtendChar (int C)
217 /* Do correct sign extension of a character */
219 if (SignedChars && (C & 0x80) != 0) {
228 static int parsechar (int c)
229 /* Parse a character. Converts \n into EOL, etc. */
234 /* Check for escape chars */
236 switch (c = gch ()) {
263 /* Hex character constant */
264 val = hexval (gch ()) << 4;
265 c = val | hexval (gch ()); /* Do not translate */
272 while ((c = *lptr) >= '0' && c <= '7' && i++ < 4) {
273 val = (val << 3) | (c - '0');
276 c = val; /* Do not translate */
279 Error (ERR_ILLEGAL_CHARCONST);
283 /* Do correct sign extension */
284 return SignExtendChar (c);
289 static void CharConst (void)
290 /* Parse a character constant. */
298 c = parsechar (cgch ());
300 /* Check for closing quote */
301 if (cgch () != '\'') {
302 Error (ERR_QUOTE_EXPECTED);
305 /* Setup values and attributes */
307 nxtval = SignExtendChar (ctrans (c)); /* Translate into target charset */
308 nxttype = type_int; /* Character constants have type int */
313 static void StringConst (void)
314 /* Parse a quoted string */
316 nxtval = GetLiteralOffs ();
319 /* Be sure to concatenate strings */
320 while (*lptr == '\"') {
322 /* Skip the quote char */
325 while (*lptr != '\"') {
327 Error (ERR_UNEXPECTED_NEWLINE);
330 AddLiteralChar (parsechar (gch()));
333 /* Skip closing quote char if there was one */
336 /* Skip white space, read new input */
341 /* Terminate the string */
342 AddLiteralChar ('\0');
348 /* Get next token from input stream */
353 /* Current token is the lookahead token */
356 /* Remember the starting position of the next token */
359 /* Skip spaces and read the next line if needed */
360 if (skipwhite () == 0) {
361 /* End of file reached */
366 /* Determine the next token from the lookahead */
371 int HaveSuffix; /* True if we have a type suffix */
372 unsigned types; /* Possible types */
374 unsigned long k; /* Value */
378 types = IT_INT | IT_LONG | IT_ULONG;
381 /* Octal or hex constants may also be of type unsigned int */
382 types = IT_INT | IT_UINT | IT_LONG | IT_ULONG;
383 /* gobble 0 and examin next char */
384 if (toupper (*++lptr) == 'X') {
387 ++lptr; /* gobble "x" */
395 k = k * base + (c - '0');
396 } else if (base == 16 && isxdigit (c)) {
397 k = (k << 4) + hexval (c);
399 break; /* not digit */
401 ++lptr; /* gobble char */
404 /* Check for a suffix */
410 if (toupper (*lptr) != 'L') {
411 types = IT_UINT | IT_ULONG;
416 } else if (c == 'L') {
419 if (toupper (*lptr) != 'U') {
420 types = IT_LONG | IT_ULONG;
429 /* Check the range to determine the type */
431 /* Out of range for int */
433 /* If the value is in the range 0x8000..0xFFFF, unsigned int is not
434 * allowed, and we don't have a type specifying suffix, emit a
437 if (k <= 0xFFFF && (types & IT_UINT) == 0 && !HaveSuffix) {
438 Warning (WARN_CONSTANT_IS_LONG);
442 /* Out of range for unsigned int */
445 if (k > 0x7FFFFFFF) {
446 /* Out of range for long int */
450 /* Now set the type string to the smallest type in types */
451 if (types & IT_INT) {
453 } else if (types & IT_UINT) {
455 } else if (types & IT_LONG) {
458 nxttype = type_ulong;
461 /* Set the value and the token */
469 /* Check for a keyword */
470 if ((nxttok = FindKey (token)) != IDENT) {
471 /* Reserved word found */
474 /* No reserved word, check for special symbols */
475 if (token [0] == '_') {
476 /* Special symbols */
477 if (strcmp (token, "__FILE__") == 0) {
478 nxtval = AddLiteral (fin);
481 } else if (strcmp (token, "__LINE__") == 0) {
486 } else if (strcmp (token, "__fixargs__") == 0) {
488 nxtval = GetParamSize (CurrentFunc);
491 } else if (strcmp (token, "__func__") == 0) {
492 /* __func__ is only defined in functions */
494 nxtval = AddLiteral (GetFuncName (CurrentFunc));
501 /* No reserved word but identifier */
502 strcpy (NextTok.Ident, token);
507 /* Monstrous switch statement ahead... */
511 if (*++lptr == '=') {
523 if (*++lptr == '=') {
556 if (*++lptr == '=') {
597 if (*++lptr == '.') {
598 if (*++lptr == '.') {
609 if (*++lptr == '=') {
630 if (*++lptr == '=') {
642 if (*++lptr == '=') {
655 if (*++lptr == '=') {
679 if (*++lptr == '=') {
712 while (*++lptr == ' ') ; /* Skip it and following whitespace */
713 if (!issym (token) || strcmp (token, "pragma") != 0) {
714 /* OOPS - should not happen */
715 Error (ERR_CPP_DIRECTIVE_EXPECTED);
729 void Consume (unsigned Token, unsigned char ErrNum)
730 /* Eat token if it is the next in the input stream, otherwise print an error
734 if (curtok == Token) {
743 void ConsumeColon (void)
744 /* Check for a colon and skip it. */
746 Consume (COLON, ERR_COLON_EXPECTED);
751 void ConsumeSemi (void)
752 /* Check for a semicolon and skip it. */
754 /* Try do be smart about typos... */
755 if (curtok == SEMI) {
758 Error (ERR_SEMICOLON_EXPECTED);
759 if (curtok == COLON || curtok == COMMA) {
767 void ConsumeLParen (void)
768 /* Check for a left parenthesis and skip it */
770 Consume (LPAREN, ERR_LPAREN_EXPECTED);
775 void ConsumeRParen (void)
776 /* Check for a right parenthesis and skip it */
778 Consume (RPAREN, ERR_RPAREN_EXPECTED);
783 void ConsumeLBrack (void)
784 /* Check for a left bracket and skip it */
786 Consume (LBRACK, ERR_LBRACK_EXPECTED);
791 void ConsumeRBrack (void)
792 /* Check for a right bracket and skip it */
794 Consume (RBRACK, ERR_RBRACK_EXPECTED);
799 void ConsumeLCurly (void)
800 /* Check for a left curly brace and skip it */
802 Consume (LCURLY, ERR_LCURLY_EXPECTED);
807 void ConsumeRCurly (void)
808 /* Check for a right curly brace and skip it */
810 Consume (RCURLY, ERR_RCURLY_EXPECTED);