| /* |
| -- |
| -- SYNOPSIS |
| -- Parse the input, and perform semantic analysis |
| -- |
| -- DESCRIPTION |
| -- This file contains the routines that parse the input makefile and |
| -- call the appropriate routines to perform the semantic analysis and |
| -- build the internal dag. |
| -- |
| -- AUTHOR |
| -- Dennis Vadura, dvadura@dmake.wticorp.com |
| -- |
| -- WWW |
| -- http://dmake.wticorp.com/ |
| -- |
| -- COPYRIGHT |
| -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved. |
| -- |
| -- This program is NOT free software; you can redistribute it and/or |
| -- modify it under the terms of the Software License Agreement Provided |
| -- in the file <distribution-root>/readme/license.txt. |
| -- |
| -- LOG |
| -- Use cvs log to obtain detailed change logs. |
| */ |
| |
| #include "extern.h" |
| |
| |
| PUBLIC void |
| Parse( fil )/* |
| ============== Parse the makefile input */ |
| FILE *fil; |
| { |
| int rule = FALSE; /* have seen a recipe line */ |
| char *p; /* termporary pointer into Buffer */ |
| char *pTmpBuf; |
| |
| DB_ENTER( "Parse" ); |
| |
| State = NORMAL_SCAN; |
| Group = FALSE; /* true if scanning a group rcpe */ |
| while( TRUE ) { |
| if( Get_line( Buffer, fil ) ) { |
| if( Group ) Fatal( "Incomplete rule recipe group detected" ); |
| |
| /* If we are still in RULE_SCAN mode there might be unbound recipes. */ |
| if( State == RULE_SCAN ) |
| Bind_rules_to_targets( F_DEFAULT ); |
| |
| if( fil != NIL( FILE ) ) /* end of parsable input */ |
| Closefile(); |
| |
| DB_VOID_RETURN; |
| } |
| else { |
| |
| #ifdef _MPW |
| if ( Buffer[0] == 10 ) |
| pTmpBuf = Buffer+1; |
| else |
| #endif |
| pTmpBuf = Buffer; |
| |
| #ifdef _MPW |
| p = pTmpBuf; |
| while ( *p ) |
| { |
| if ( *p == 10 ) |
| *p = '\t'; |
| p++; |
| } |
| #endif |
| |
| switch( State ) { |
| case RULE_SCAN: |
| |
| /* Check for the `[' that starts off a group recipe definition. |
| * It must appear as the first non-white space |
| * character in the line. */ |
| |
| p = DmStrSpn( Buffer, " \t\r\n" ); |
| if( Set_group_attributes( p ) ) { |
| if( Group ) |
| Fatal( "New group recipe begin found within group recipe." ); |
| else if( rule ) |
| Fatal( "Cannot mix single and group recipe lines." ); |
| else |
| Group = TRUE; |
| |
| rule = TRUE; |
| |
| break; /* ignore the group start */ |
| } |
| |
| if( Group ) { |
| if( *p != ']' ) { |
| Add_recipe_to_list( pTmpBuf, TRUE, TRUE ); |
| rule = TRUE; |
| } |
| else |
| State = NORMAL_SCAN; |
| } |
| else { |
| if( *pTmpBuf == '\t' |
| || (Notabs && *pTmpBuf == ' ') ) { |
| Add_recipe_to_list( pTmpBuf, FALSE, FALSE ); |
| rule = TRUE; |
| } |
| else if( *p == ']' ) |
| Fatal( "Found unmatched ']'" ); |
| else if( *pTmpBuf ) /* Something that was no recipe. */ |
| State = NORMAL_SCAN; |
| /* The only thing that was not handled was an empty line. */ |
| } |
| |
| if( State == RULE_SCAN ) break; /* ie. keep going */ |
| |
| Bind_rules_to_targets( (Group) ? F_GROUP: F_DEFAULT ); |
| |
| rule = FALSE; |
| if( Group ) { |
| Group = FALSE; |
| break; |
| } |
| /*FALLTRHOUGH*/ |
| |
| /* In this case we broke out of the rule scan because we do not |
| * have a recipe line that begins with a <TAB>, so lets |
| * try to scan the thing as a macro or rule definition. */ |
| |
| |
| case NORMAL_SCAN: |
| if( !*pTmpBuf ) continue; /* we have null input line */ |
| |
| /* STUPID AUGMAKE uses "include" at the start of a line as |
| * a signal to include a new file, so let's look for it. |
| * if we see it replace it by .INCLUDE: and stick this back |
| * into the buffer. */ |
| if( !strncmp( "include", pTmpBuf, 7 ) && |
| (pTmpBuf[7] == ' ' || pTmpBuf[7] == '\t') ) |
| { |
| char *tmp; |
| |
| tmp = DmStrJoin( ".INCLUDE:", pTmpBuf+7, -1, FALSE ); |
| strcpy( pTmpBuf, tmp ); |
| FREE( tmp ); |
| } |
| |
| /* look for a macro definition, they all contain an = sign |
| * if we fail to recognize it as a legal macro op then try to |
| * parse the same line as a rule definition, it's one or the |
| * other */ |
| |
| if( Parse_macro(pTmpBuf, M_DEFAULT) ) break;/* it's a macro def*/ |
| if( Parse_rule_def( &State ) ) break;/* it's a rule def */ |
| |
| /* if it is an empty or blank line then ignore it */ |
| if( !*Buffer || *DmStrSpn( Buffer, " \t\r\n" ) == '\0' ) break; |
| |
| /* otherwise assume it was a line of unrecognized input, or a |
| * recipe line out of place so print a message */ |
| |
| Fatal( "Expecting macro or rule defn, found neither" ); |
| break; |
| |
| default: |
| Fatal( "Internal -- UNKNOWN Parser state %d", State ); |
| } |
| } |
| } |
| } |
| |