Support for Mac OS X powerpc register names (based on a patch by
[wine/multimedia.git] / tools / winebuild / parser.c
blob8cca02ede0e3c73c8da8d57c60657e27ecd12d41
1 /*
2 * Spec file parser
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Martin von Loewis
6 * Copyright 1995, 1996, 1997 Alexandre Julliard
7 * Copyright 1997 Eric Youngdale
8 * Copyright 1999 Ulrich Weigand
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
34 #include "winbase.h"
35 #include "build.h"
37 int current_line = 0;
39 static char ParseBuffer[512];
40 static char TokenBuffer[512];
41 static char *ParseNext = ParseBuffer;
42 static FILE *input_file;
44 static const char * const TypeNames[TYPE_NBTYPES] =
46 "variable", /* TYPE_VARIABLE */
47 "pascal16", /* TYPE_PASCAL_16 */
48 "pascal", /* TYPE_PASCAL */
49 "equate", /* TYPE_ABS */
50 "stub", /* TYPE_STUB */
51 "stdcall", /* TYPE_STDCALL */
52 "cdecl", /* TYPE_CDECL */
53 "varargs", /* TYPE_VARARGS */
54 "extern" /* TYPE_EXTERN */
57 static const char * const FlagNames[] =
59 "norelay", /* FLAG_NORELAY */
60 "noname", /* FLAG_NONAME */
61 "ret64", /* FLAG_RET64 */
62 "i386", /* FLAG_I386 */
63 "register", /* FLAG_REGISTER */
64 "interrupt", /* FLAG_INTERRUPT */
65 "private", /* FLAG_PRIVATE */
66 NULL
69 static int IsNumberString(const char *s)
71 while (*s) if (!isdigit(*s++)) return 0;
72 return 1;
75 inline static int is_token_separator( char ch )
77 return (ch == '(' || ch == ')' || ch == '-');
80 /* get the next line from the input file, or return 0 if at eof */
81 static int get_next_line(void)
83 ParseNext = ParseBuffer;
84 current_line++;
85 return (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) != NULL);
88 static const char * GetToken( int allow_eol )
90 char *p = ParseNext;
91 char *token = TokenBuffer;
93 for (;;)
95 /* remove initial white space */
96 p = ParseNext;
97 while (isspace(*p)) p++;
99 if (*p == '\\' && p[1] == '\n') /* line continuation */
101 if (!get_next_line())
103 if (!allow_eol) error( "Unexpected end of file\n" );
104 return NULL;
107 else break;
110 if ((*p == '\0') || (*p == '#'))
112 if (!allow_eol) error( "Declaration not terminated properly\n" );
113 return NULL;
117 * Find end of token.
119 if (is_token_separator(*p))
121 /* a separator is always a complete token */
122 *token++ = *p++;
124 else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
126 if (*p == '\\') p++;
127 if (*p) *token++ = *p++;
129 *token = '\0';
130 ParseNext = p;
131 return TokenBuffer;
135 /*******************************************************************
136 * ParseVariable
138 * Parse a variable definition.
140 static int ParseVariable( ORDDEF *odp )
142 char *endptr;
143 int *value_array;
144 int n_values;
145 int value_array_size;
146 const char *token;
148 if (SpecType == SPEC_WIN32)
150 error( "'variable' not supported in Win32, use 'extern' instead\n" );
151 return 0;
154 if (!(token = GetToken(0))) return 0;
155 if (*token != '(')
157 error( "Expected '(' got '%s'\n", token );
158 return 0;
161 n_values = 0;
162 value_array_size = 25;
163 value_array = xmalloc(sizeof(*value_array) * value_array_size);
165 for (;;)
167 if (!(token = GetToken(0)))
169 free( value_array );
170 return 0;
172 if (*token == ')')
173 break;
175 value_array[n_values++] = strtol(token, &endptr, 0);
176 if (n_values == value_array_size)
178 value_array_size += 25;
179 value_array = xrealloc(value_array,
180 sizeof(*value_array) * value_array_size);
183 if (endptr == NULL || *endptr != '\0')
185 error( "Expected number value, got '%s'\n", token );
186 free( value_array );
187 return 0;
191 odp->u.var.n_values = n_values;
192 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
193 return 1;
197 /*******************************************************************
198 * ParseExportFunction
200 * Parse a function definition.
202 static int ParseExportFunction( ORDDEF *odp )
204 const char *token;
205 unsigned int i;
207 switch(SpecType)
209 case SPEC_WIN16:
210 if (odp->type == TYPE_STDCALL)
212 error( "'stdcall' not supported for Win16\n" );
213 return 0;
215 if (odp->type == TYPE_VARARGS)
217 error( "'varargs' not supported for Win16\n" );
218 return 0;
220 break;
221 case SPEC_WIN32:
222 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
224 error( "'pascal' not supported for Win32\n" );
225 return 0;
227 if (odp->flags & FLAG_INTERRUPT)
229 error( "'interrupt' not supported for Win32\n" );
230 return 0;
232 break;
233 default:
234 break;
237 if (!(token = GetToken(0))) return 0;
238 if (*token != '(')
240 error( "Expected '(' got '%s'\n", token );
241 return 0;
244 for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
246 if (!(token = GetToken(0))) return 0;
247 if (*token == ')')
248 break;
250 if (!strcmp(token, "word"))
251 odp->u.func.arg_types[i] = 'w';
252 else if (!strcmp(token, "s_word"))
253 odp->u.func.arg_types[i] = 's';
254 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
255 odp->u.func.arg_types[i] = 'l';
256 else if (!strcmp(token, "ptr"))
257 odp->u.func.arg_types[i] = 'p';
258 else if (!strcmp(token, "str"))
259 odp->u.func.arg_types[i] = 't';
260 else if (!strcmp(token, "wstr"))
261 odp->u.func.arg_types[i] = 'W';
262 else if (!strcmp(token, "segstr"))
263 odp->u.func.arg_types[i] = 'T';
264 else if (!strcmp(token, "double"))
266 odp->u.func.arg_types[i++] = 'l';
267 if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
269 else
271 error( "Unknown argument type '%s'\n", token );
272 return 0;
275 if (SpecType == SPEC_WIN32)
277 if (strcmp(token, "long") &&
278 strcmp(token, "ptr") &&
279 strcmp(token, "str") &&
280 strcmp(token, "wstr") &&
281 strcmp(token, "double"))
283 error( "Type '%s' not supported for Win32\n", token );
284 return 0;
288 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
290 error( "Too many arguments\n" );
291 return 0;
294 odp->u.func.arg_types[i] = '\0';
295 if (odp->type == TYPE_VARARGS)
296 odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
298 if (!(token = GetToken(1)))
300 if (!strcmp( odp->name, "@" ))
302 error( "Missing handler name for anonymous function\n" );
303 return 0;
305 odp->link_name = xstrdup( odp->name );
307 else
309 odp->link_name = xstrdup( token );
310 if (strchr( odp->link_name, '.' ))
312 if (SpecType == SPEC_WIN16)
314 error( "Forwarded functions not supported for Win16\n" );
315 return 0;
317 odp->flags |= FLAG_FORWARD;
320 return 1;
324 /*******************************************************************
325 * ParseEquate
327 * Parse an 'equate' definition.
329 static int ParseEquate( ORDDEF *odp )
331 char *endptr;
332 int value;
333 const char *token;
335 if (SpecType == SPEC_WIN32)
337 error( "'equate' not supported for Win32\n" );
338 return 0;
340 if (!(token = GetToken(0))) return 0;
341 value = strtol(token, &endptr, 0);
342 if (endptr == NULL || *endptr != '\0')
344 error( "Expected number value, got '%s'\n", token );
345 return 0;
347 odp->u.abs.value = value;
348 return 1;
352 /*******************************************************************
353 * ParseStub
355 * Parse a 'stub' definition.
357 static int ParseStub( ORDDEF *odp )
359 odp->u.func.arg_types[0] = '\0';
360 odp->link_name = xstrdup("");
361 return 1;
365 /*******************************************************************
366 * ParseExtern
368 * Parse an 'extern' definition.
370 static int ParseExtern( ORDDEF *odp )
372 const char *token;
374 if (SpecType == SPEC_WIN16)
376 error( "'extern' not supported for Win16, use 'variable' instead\n" );
377 return 0;
379 if (!(token = GetToken(1)))
381 if (!strcmp( odp->name, "@" ))
383 error( "Missing handler name for anonymous extern\n" );
384 return 0;
386 odp->link_name = xstrdup( odp->name );
388 else
390 odp->link_name = xstrdup( token );
391 if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
393 return 1;
397 /*******************************************************************
398 * ParseFlags
400 * Parse the optional flags for an entry point
402 static const char *ParseFlags( ORDDEF *odp )
404 unsigned int i;
405 const char *token;
409 if (!(token = GetToken(0))) break;
410 for (i = 0; FlagNames[i]; i++)
411 if (!strcmp( FlagNames[i], token )) break;
412 if (!FlagNames[i])
414 error( "Unknown flag '%s'\n", token );
415 return NULL;
417 odp->flags |= 1 << i;
418 token = GetToken(0);
419 } while (token && *token == '-');
421 return token;
424 /*******************************************************************
425 * fix_export_name
427 * Fix an exported function name by removing a possible @xx suffix
429 static void fix_export_name( char *name )
431 char *p, *end = strrchr( name, '@' );
432 if (!end || !end[1] || end == name) return;
433 /* make sure all the rest is digits */
434 for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
435 *end = 0;
438 /*******************************************************************
439 * ParseOrdinal
441 * Parse an ordinal definition.
443 static int ParseOrdinal(int ordinal)
445 const char *token;
447 ORDDEF *odp = xmalloc( sizeof(*odp) );
448 memset( odp, 0, sizeof(*odp) );
449 EntryPoints[nb_entry_points++] = odp;
451 if (!(token = GetToken(0))) goto error;
453 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
454 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
455 break;
457 if (odp->type >= TYPE_NBTYPES)
459 error( "Expected type after ordinal, found '%s' instead\n", token );
460 goto error;
463 if (!(token = GetToken(0))) goto error;
464 if (*token == '-' && !(token = ParseFlags( odp ))) goto error;
466 odp->name = xstrdup( token );
467 fix_export_name( odp->name );
468 odp->lineno = current_line;
469 odp->ordinal = ordinal;
471 switch(odp->type)
473 case TYPE_VARIABLE:
474 if (!ParseVariable( odp )) goto error;
475 break;
476 case TYPE_PASCAL_16:
477 case TYPE_PASCAL:
478 case TYPE_STDCALL:
479 case TYPE_VARARGS:
480 case TYPE_CDECL:
481 if (!ParseExportFunction( odp )) goto error;
482 break;
483 case TYPE_ABS:
484 if (!ParseEquate( odp )) goto error;
485 break;
486 case TYPE_STUB:
487 if (!ParseStub( odp )) goto error;
488 break;
489 case TYPE_EXTERN:
490 if (!ParseExtern( odp )) goto error;
491 break;
492 default:
493 assert( 0 );
496 #ifndef __i386__
497 if (odp->flags & FLAG_I386)
499 /* ignore this entry point on non-Intel archs */
500 EntryPoints[--nb_entry_points] = NULL;
501 free( odp );
502 return 1;
504 #endif
506 if (ordinal != -1)
508 if (!ordinal)
510 error( "Ordinal 0 is not valid\n" );
511 goto error;
513 if (ordinal >= MAX_ORDINALS)
515 error( "Ordinal number %d too large\n", ordinal );
516 goto error;
518 if (ordinal > Limit) Limit = ordinal;
519 if (ordinal < Base) Base = ordinal;
520 odp->ordinal = ordinal;
521 if (Ordinals[ordinal])
523 error( "Duplicate ordinal %d\n", ordinal );
524 goto error;
526 Ordinals[ordinal] = odp;
529 if (!strcmp( odp->name, "@" ) || odp->flags & FLAG_NONAME)
531 if (ordinal == -1)
533 error( "Nameless function needs an explicit ordinal number\n" );
534 goto error;
536 if (SpecType != SPEC_WIN32)
538 error( "Nameless functions not supported for Win16\n" );
539 goto error;
541 if (!strcmp( odp->name, "@" )) free( odp->name );
542 else odp->export_name = odp->name;
543 odp->name = NULL;
545 else Names[nb_names++] = odp;
546 return 1;
548 error:
549 EntryPoints[--nb_entry_points] = NULL;
550 free( odp->name );
551 free( odp );
552 return 0;
556 static int name_compare( const void *name1, const void *name2 )
558 ORDDEF *odp1 = *(ORDDEF **)name1;
559 ORDDEF *odp2 = *(ORDDEF **)name2;
560 return strcmp( odp1->name, odp2->name );
563 /*******************************************************************
564 * sort_names
566 * Sort the name array and catch duplicates.
568 static void sort_names(void)
570 int i;
572 if (!nb_names) return;
574 /* sort the list of names */
575 qsort( Names, nb_names, sizeof(Names[0]), name_compare );
577 /* check for duplicate names */
578 for (i = 0; i < nb_names - 1; i++)
580 if (!strcmp( Names[i]->name, Names[i+1]->name ))
582 current_line = max( Names[i]->lineno, Names[i+1]->lineno );
583 error( "'%s' redefined\n%s:%d: First defined here\n",
584 Names[i]->name, input_file_name,
585 min( Names[i]->lineno, Names[i+1]->lineno ) );
591 /*******************************************************************
592 * ParseTopLevel
594 * Parse a spec file.
596 int ParseTopLevel( FILE *file )
598 const char *token;
600 input_file = file;
601 current_line = 0;
603 while (get_next_line())
605 if (!(token = GetToken(1))) continue;
606 if (strcmp(token, "@") == 0)
608 if (SpecType != SPEC_WIN32)
610 error( "'@' ordinals not supported for Win16\n" );
611 continue;
613 if (!ParseOrdinal( -1 )) continue;
615 else if (IsNumberString(token))
617 if (!ParseOrdinal( atoi(token) )) continue;
619 else
621 error( "Expected ordinal declaration, got '%s'\n", token );
622 continue;
624 if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
627 current_line = 0; /* no longer parsing the input file */
628 sort_names();
629 return !nb_errors;
633 /*******************************************************************
634 * add_debug_channel
636 static void add_debug_channel( const char *name )
638 int i;
640 for (i = 0; i < nb_debug_channels; i++)
641 if (!strcmp( debug_channels[i], name )) return;
643 debug_channels = xrealloc( debug_channels, (nb_debug_channels + 1) * sizeof(*debug_channels));
644 debug_channels[nb_debug_channels++] = xstrdup(name);
648 /*******************************************************************
649 * parse_debug_channels
651 * Parse a source file and extract the debug channel definitions.
653 int parse_debug_channels( const char *srcdir, const char *filename )
655 FILE *file;
656 int eol_seen = 1;
658 file = open_input_file( srcdir, filename );
659 while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
661 char *channel, *end, *p = ParseBuffer;
663 p = ParseBuffer + strlen(ParseBuffer) - 1;
664 if (!eol_seen) /* continuation line */
666 eol_seen = (*p == '\n');
667 continue;
669 if ((eol_seen = (*p == '\n'))) *p = 0;
671 p = ParseBuffer;
672 while (isspace(*p)) p++;
673 if (!memcmp( p, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
674 !memcmp( p, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
676 p += 26;
677 while (isspace(*p)) p++;
678 if (*p != '(')
680 error( "invalid debug channel specification '%s'\n", ParseBuffer );
681 goto next;
683 p++;
684 while (isspace(*p)) p++;
685 if (!isalpha(*p))
687 error( "invalid debug channel specification '%s'\n", ParseBuffer );
688 goto next;
690 channel = p;
691 while (isalnum(*p) || *p == '_') p++;
692 end = p;
693 while (isspace(*p)) p++;
694 if (*p != ')')
696 error( "invalid debug channel specification '%s'\n", ParseBuffer );
697 goto next;
699 *end = 0;
700 add_debug_channel( channel );
702 next:
703 current_line++;
705 close_input_file( file );
706 return !nb_errors;