/* $RCSfile: parse.c,v $
-- $Revision: 1.7.6.1 $
-- last change: $Author: vq $ $Date: 2007/08/09 01:43:17 $
--
-- 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 );
	 }
      }
   }
}



syntax highlighted by Code2HTML, v. 0.9.1