internal static ParseResult parseQuotes( Interp interp, string inString, int index, int length )
    {
      TclObject obj;
      TclParse parse = null;
      TclToken token;
      CharPointer script;

      try
      {

        script = new CharPointer( inString );
        script.index = index;

        parse = new TclParse( interp, script.array, length, null, 0 );

        System.Diagnostics.Debug.WriteLine( "string is \"" + inString + "\"" );
        System.Diagnostics.Debug.WriteLine( "script.array is \"" + new string( script.array ) + "\"" );

        System.Diagnostics.Debug.WriteLine( "index is " + index );
        System.Diagnostics.Debug.WriteLine( "length is " + length );

        System.Diagnostics.Debug.WriteLine( "parse.endIndex is " + parse.endIndex );


        parse.commandStart = script.index;
        token = parse.getToken( 0 );
        token.type = Parser.TCL_TOKEN_WORD;
        token.script_array = script.array;
        token.script_index = script.index;
        parse.numTokens++;
        parse.numWords++;
        parse = Parser.parseTokens( script.array, script.index, Parser.TYPE_QUOTE, parse );

        // Check for the error condition where the parse did not end on
        // a '"' char. Is this happened raise an error.

        if ( script.array[parse.termIndex] != '"' )
        {
          throw new TclException( interp, "missing \"" );
        }

        // if there was no error then parsing will continue after the
        // last char that was parsed from the string

        script.index = parse.termIndex + 1;

        // Finish filling in the token for the word and check for the
        // special case of a word consisting of a single range of
        // literal text.

        token = parse.getToken( 0 );
        token.size = script.index - token.script_index;
        token.numComponents = parse.numTokens - 1;
        if ( ( token.numComponents == 1 ) && ( parse.getToken( 1 ).type == Parser.TCL_TOKEN_TEXT ) )
        {
          token.type = Parser.TCL_TOKEN_SIMPLE_WORD;
        }
        parse.commandSize = script.index - parse.commandStart;
        if ( parse.numTokens > 0 )
        {
          obj = Parser.evalTokens( interp, parse.tokenList, 1, parse.numTokens - 1 );
        }
        else
        {
          throw new TclRuntimeError( "parseQuotes error: null obj result" );
        }
      }
      finally
      {
        parse.release();
      }

      return ( new ParseResult( obj, script.index ) );
    }
Exemple #2
0
    internal static TclParse parseTokens( char[] script_array, int script_index, int mask, TclParse parse )
    // Information about parse in progress.
    // Updated with additional tokens and
    // termination information. 
    {
      char cur;
      int type, originalTokens, varToken;
      TclToken token;
      TclParse nested;
      BackSlashResult bs;



#if DEBUG
				System.Diagnostics.Debug.WriteLine();
				System.Diagnostics.Debug.WriteLine("Entered Parser.parseTokens()");
				System.Diagnostics.Debug.Write("now to parse the string \"");
				for (int k = script_index; k < script_array.Length; k++)
				{
					System.Diagnostics.Debug.Write(script_array[k]);
				}
				System.Diagnostics.Debug.WriteLine("\"");
#endif


      // Each iteration through the following loop adds one token of
      // type TCL_TOKEN_TEXT, TCL_TOKEN_BS, TCL_TOKEN_COMMAND, or
      // TCL_TOKEN_VARIABLE to parse.  For TCL_TOKEN_VARIABLE additional,
      // tokens tokens are added for the parsed variable name.

      originalTokens = parse.numTokens;
      while ( true )
      {
        token = parse.getToken( parse.numTokens );
        token.script_array = script_array;
        token.script_index = script_index;
        token.numComponents = 0;

#if DEBUG
					System.Diagnostics.Debug.WriteLine();
					System.Diagnostics.Debug.WriteLine("Now on index " + script_index);
					char tmp_c = script_array[script_index];
					System.Diagnostics.Debug.WriteLine("Char is '" + tmp_c + "'");
					System.Diagnostics.Debug.WriteLine("Unicode id is " + ((int) tmp_c));
					int tmp_i = ((int) ((tmp_c > TYPE_MAX)?TYPE_NORMAL:typeTable[tmp_c]));
					System.Diagnostics.Debug.WriteLine("Type is " + tmp_i);
					System.Diagnostics.Debug.WriteLine("Mask is " + mask);
					System.Diagnostics.Debug.WriteLine("(type & mask) is " + ((int) (tmp_i & mask)));
					System.Diagnostics.Debug.WriteLine("orig token.size is " + token.size);
#endif


        cur = script_array[script_index];
        type = ( ( cur > TYPE_MAX ) ? TYPE_NORMAL : typeTable[cur] );

        if ( ( type & mask ) != 0 )
        {
          System.Diagnostics.Debug.WriteLine( "mask break" );
          break;
        }

        if ( ( type & TYPE_SUBS ) == 0 )
        {
          // This is a simple range of characters.  Scan to find the end
          // of the range.

          System.Diagnostics.Debug.WriteLine( "simple range" );

          while ( true )
          {
            cur = script_array[++script_index];
            type = ( ( cur > TYPE_MAX ) ? TYPE_NORMAL : typeTable[cur] );

            System.Diagnostics.Debug.WriteLine( "skipping '" + cur + "'" );

            if ( ( type & ( mask | TYPE_SUBS ) ) != 0 )
            {
              break;
            }
          }
          token.type = TCL_TOKEN_TEXT;
          token.size = script_index - token.script_index;
          parse.numTokens++;

          System.Diagnostics.Debug.WriteLine( "end simple range" );
          System.Diagnostics.Debug.WriteLine( "token.size is " + token.size );
          System.Diagnostics.Debug.WriteLine( "parse.numTokens is " + parse.numTokens );
        }
        else if ( cur == '$' )
        {
          // This is a variable reference.  Call parseVarName to do
          // all the dirty work of parsing the name.

          System.Diagnostics.Debug.WriteLine( "dollar sign" );

          varToken = parse.numTokens;
          parse = parseVarName( parse.interp, script_array, script_index, parse.endIndex - script_index, parse, true );
          if ( parse.result != TCL.CompletionCode.OK )
          {
            return parse;
          }
          script_index += parse.getToken( varToken ).size;
        }
        else if ( cur == '[' )
        {
          // Command substitution.  Call parseCommand recursively
          // (and repeatedly) to parse the nested command(s), then
          // throw away the parse information.

          System.Diagnostics.Debug.WriteLine( "command" );

          script_index++;
          while ( true )
          {
            nested = parseCommand( parse.interp, script_array, script_index, parse.endIndex - script_index, parse.fileName, parse.lineNum, true );
            if ( nested.result != TCL.CompletionCode.OK )
            {
              parse.termIndex = nested.termIndex;
              parse.incomplete = nested.incomplete;
              parse.result = nested.result;
              return parse;
            }
            script_index = nested.commandStart + nested.commandSize;
            if ( ( script_array[script_index - 1] == ']' ) && !nested.incomplete )
            {
              break;
            }
            if ( script_index == parse.endIndex )
            {
              if ( parse.interp != null )
              {
                parse.interp.setResult( "missing close-bracket" );
              }
              parse.termIndex = token.script_index;
              parse.incomplete = true;
              parse.result = TCL.CompletionCode.ERROR;
              return parse;
            }
          }
          token.type = TCL_TOKEN_COMMAND;
          token.size = script_index - token.script_index;
          parse.numTokens++;
        }
        else if ( cur == '\\' )
        {
          // Backslash substitution.

          System.Diagnostics.Debug.WriteLine( "backslash" );

          if ( script_array[script_index + 1] == '\n' )
          {
            if ( ( script_index + 2 ) == parse.endIndex )
            {
              parse.incomplete = true;
            }

            // Note: backslash-newline is special in that it is
            // treated the same as a space character would be.  This
            // means that it could terminate the token.

            if ( ( mask & TYPE_SPACE ) != 0 )
            {
              break;
            }
          }
          token.type = TCL_TOKEN_BS;
          bs = backslash( script_array, script_index );
          token.size = bs.nextIndex - script_index;
          parse.numTokens++;
          script_index += token.size;
        }
        else if ( cur == '\x0000' )
        {
          // We encountered a null character.  If it is the null
          // character at the end of the string, then return.
          // Otherwise generate a text token for the single
          // character.

          System.Diagnostics.Debug.WriteLine( "null char" );
          System.Diagnostics.Debug.WriteLine( "script_index is " + script_index );
          System.Diagnostics.Debug.WriteLine( "parse.endIndex is " + parse.endIndex );

          if ( script_index == parse.endIndex )
          {
            break;
          }

          token.type = TCL_TOKEN_TEXT;
          token.size = 1;
          parse.numTokens++;
          script_index++;
        }
        else
        {
          throw new TclRuntimeError( "parseTokens encountered unknown character" );
        }
      } // end while (true)


      if ( parse.numTokens == originalTokens )
      {
        // There was nothing in this range of text.  Add an empty token
        // for the empty range, so that there is always at least one
        // token added.

        System.Diagnostics.Debug.WriteLine( "empty token" );

        token.type = TCL_TOKEN_TEXT;
        token.size = 0;
        parse.numTokens++;
      }
      else
      {
        System.Diagnostics.Debug.WriteLine( "non empty token case" );
      }

      parse.termIndex = script_index;
      parse.result = TCL.CompletionCode.OK;

#if DEBUG			
				System.Diagnostics.Debug.WriteLine();
				System.Diagnostics.Debug.WriteLine("Leaving Parser.parseTokens()");
				
				System.Diagnostics.Debug.WriteLine("after parse, parse.numTokens is " + parse.numTokens);
				System.Diagnostics.Debug.WriteLine("after parse, token.size is " + token.size);
				System.Diagnostics.Debug.WriteLine("after parse, token.hashCode() is " + token.GetHashCode());
				
				
				//System.out.println( parse.toString() );
				
				
				System.Diagnostics.Debug.Write("printing " + (parse.numTokens - originalTokens) + " token(s)");
				
				for (int k = originalTokens; k < parse.numTokens; k++)
				{
					token = parse.getToken(k);
					System.Diagnostics.Debug.WriteLine(token);
				}
				
				System.Diagnostics.Debug.WriteLine("done printing tokens");
#endif

      return parse;
    }
Exemple #3
0
    public static TclParse parseCommand( Interp interp, char[] script_array, int script_index, int numBytes, string fileName, int lineNum, bool nested )
    // True means that this is a nested command:
    // close bracket should be considered
    // a command terminator.  If false, then close
    // bracket has no special meaning. 
    {

      char cur; //the char we are currently parsing
      int type; // Result returned by charType(src.charAt()). 
      TclToken token; // Pointer to token being filled in. 
      int wordIndex; // Index of word token for current word. 
      int level; // Nesting level of curly braces: gives
      // number of right braces we must find to
      // end word. 
      TclParse parse; // Return value to fill in with information
      // about the parsed command.
      int terminators; // charType() bits that indicate the end
      // of a command. 
      BackSlashResult bs; // Result of a call to backslash(...).
      int endIndex; // Index that points to the character after
      // the last character to be parsed.
      char savedChar; // To terminate the parsing correctly, the
      // character at endIndex is set to \0.  This
      // stores the value to return when finished.


      int saved_script_index = script_index; //save the original index


      int script_length = script_array.Length - 1;


      if ( numBytes < 0 )
      {
        numBytes = script_length - script_index;
      }
      endIndex = script_index + numBytes;
      if ( endIndex > script_length )
      {
        endIndex = script_length;
      }

      savedChar = script_array[endIndex];
      script_array[endIndex] = '\x0000';

      parse = new TclParse( interp, script_array, endIndex, fileName, lineNum );

      if ( nested )
      {
        terminators = TYPE_COMMAND_END | TYPE_CLOSE_BRACK;
      }
      else
      {
        terminators = TYPE_COMMAND_END;
      }

      // Parse any leading space and comments before the first word of the
      // command.


      try
      {

        while ( true )
        {

          cur = script_array[script_index];

          while ( ( ( cur <= TYPE_MAX ) && ( typeTable[cur] == TYPE_SPACE ) ) || ( cur == '\n' ) )
          {
            cur = script_array[++script_index];
          }

          if ( ( cur == '\\' ) && ( script_array[script_index + 1] == '\n' ) )
          {

            // Skip backslash-newline sequence: it should be treated
            // just like white space.

            if ( ( script_index + 2 ) == parse.endIndex )
            {
              parse.incomplete = true;
            }

            //this will add 2 to the offset and return to the top
            //of the while(true) loop which will get the next cur

            script_index += 2;
            continue;
          }

          // If we have found the start of a command goto the word parsing loop
          if ( cur != '#' )
          {
            break;
          }

          // Record the index where the comment starts
          if ( parse.commentStart < 0 )
          {
            parse.commentStart = script_index;
          }

          while ( true )
          {
            cur = script_array[script_index];
            if ( script_index == parse.endIndex )
            {
              if ( nested )
                parse.incomplete = true;
              parse.commentSize = script_index - parse.commentStart;
              break;
            }
            else if ( cur == '\\' )
            {
              if ( ( script_array[script_index + 1] == '\n' ) && ( ( script_index + 2 ) == parse.endIndex ) )
              {
                parse.incomplete = true;
              }
              bs = backslash( script_array, script_index );
              script_index = bs.nextIndex;
            }
            else if ( cur == '\n' )
            {
              script_index++;
              parse.commentSize = script_index - parse.commentStart;
              break;
            }
            else
            {
              script_index++;
            }
          }
        }



        // The following loop parses the words of the command, one word
        // in each iteration through the loop.

        parse.commandStart = script_index;

        while ( true )
        {

          bool expandWord = false;

          // Create the token for  the word.
          wordIndex = parse.numTokens;

          token = parse.getToken( wordIndex );
          token.type = TCL_TOKEN_WORD;

          // Skip white space before the word. Also skip a backslash-newline
          // sequence: it should be treated just like white space.


          while ( true )
          {
            cur = script_array[script_index];
            type = ( ( cur > TYPE_MAX ) ? TYPE_NORMAL : typeTable[cur] );

            if ( type == TYPE_SPACE )
            {
              script_index++;
              continue;
            }
            else if ( ( cur == '\\' ) && ( script_array[script_index + 1] == '\n' ) )
            {
              if ( ( script_index + 2 ) == parse.endIndex )
              {
                parse.incomplete = true;
              }
              bs = backslash( script_array, script_index );
              script_index = bs.nextIndex;
              continue;
            }
            break;
          }

          if ( ( type & terminators ) != 0 )
          {
            script_index++;
            break;
          }

          if ( script_index == parse.endIndex )
          {
            if ( nested && savedChar != ']' )
            {
              parse.incomplete = true;
              throw new TclException( interp, "missing close-bracket" );
            }
            break;
          }

          token.script_array = script_array;
          token.script_index = script_index;

          parse.numTokens++;
          parse.numWords++;


        // At this point the word can have one of four forms: something
// enclosed in quotes, something enclosed in braces, and
// expanding word, or an unquoted word (anything else).

parseWord:
          cur = script_array[script_index];

          if ( cur == '"' )
          {
            script_index++;
            parse = parseTokens( script_array, script_index, TYPE_QUOTE, parse );
            if ( parse.result != TCL.CompletionCode.OK )
            {
              throw new TclException( parse.result );
            }
            if ( parse.inString[parse.termIndex] != '"' )
            {
              parse.termIndex = script_index - 1;
              parse.incomplete = true;
              throw new TclException( parse.interp, "missing \"" );
            }
            script_index = parse.termIndex + 1;
          }
          else if ( cur == '{' )
          {
            /*
             * Hack for {*} 
             * Check whether the braces contained the word expansion prefix.
             */
            if ( script_index < script_array.Length - 3 // only if there is room
              && script_array[script_index + 1] == '*' && script_array[script_index + 2] == '}' // and it is {*}
              && typeTable[script_array[script_index + 1]] != TYPE_SPACE /* Non-whitespace follows */
              && !expandWord // only one per token
              )
            {
              script_index += 3; // Skip
              expandWord = true;
              //parse.numTokens--;
              goto parseWord;
            }

            // Find the matching right brace that terminates the word,
            // then generate a single token for everything between the
            // braces.

            script_index++;
            token = parse.getToken( parse.numTokens );
            token.type = TCL_TOKEN_TEXT;
            token.script_array = script_array;
            token.script_index = script_index;
            token.numComponents = 0;
            level = 1;
            while ( true )
            {
              cur = script_array[script_index];

              // get the current char in the array and lookup its type
              while ( ( ( cur > TYPE_MAX ) ? TYPE_NORMAL : typeTable[cur] ) == TYPE_NORMAL )
              {
                cur = script_array[++script_index];
              }
              if ( script_array[script_index] == '}' )
              {
                level--;
                if ( level == 0 )
                {
                  break;
                }
                script_index++;
              }
              else if ( script_array[script_index] == '{' )
              {
                level++;
                script_index++;
              }
              else if ( script_array[script_index] == '\\' )
              {
                bs = backslash( script_array, script_index );
                if ( script_array[script_index + 1] == '\n' )
                {
                  // A backslash-newline sequence requires special
                  // treatment: it must be collapsed, even inside
                  // braces, so we have to split the word into
                  // multiple tokens so that the backslash-newline
                  // can be represented explicitly.

                  if ( ( script_index + 2 ) == parse.endIndex )
                  {
                    parse.incomplete = true;
                  }
                  token.size = script_index - token.script_index;
                  if ( token.size != 0 )
                  {
                    parse.numTokens++;
                  }
                  token = parse.getToken( parse.numTokens );
                  token.type = TCL_TOKEN_BS;
                  token.script_array = script_array;
                  token.script_index = script_index;
                  token.size = bs.nextIndex - script_index;
                  token.numComponents = 0;
                  parse.numTokens++;
                  script_index = bs.nextIndex;
                  token = parse.getToken( parse.numTokens );
                  token.type = TCL_TOKEN_TEXT;
                  token.script_array = script_array;
                  token.script_index = script_index;
                  token.numComponents = 0;
                }
                else
                {
                  script_index = bs.nextIndex;
                }
              }
              else if ( script_index == parse.endIndex )
              {
                parse.termIndex = parse.getToken( wordIndex ).script_index;
                parse.incomplete = true;
                throw new TclException( interp, "missing close-brace" );
              }
              else
              {
                script_index++;
              }
            }
            if ( ( script_index != token.script_index ) || ( parse.numTokens == ( wordIndex + 1 ) ) )
            {
              token.size = script_index - token.script_index;
              parse.numTokens++;
            }
            script_index++;
          }
          else
          {
            // This is an unquoted word.  Call parseTokens and let it do
            // all of the work.

            parse = parseTokens( script_array, script_index, TYPE_SPACE | terminators, parse );
            if ( parse.result != TCL.CompletionCode.OK )
            {
              throw new TclException( parse.result );
            }
            script_index = parse.termIndex;
          }

          // Finish filling in the token for the word and check for the
          // special case of a word consisting of a single range of
          // literal text.

          token = parse.getToken( wordIndex );
          token.size = script_index - token.script_index;
          token.numComponents = parse.numTokens - ( wordIndex + 1 );

          if ( expandWord )
          {
            int i = 1;
            bool isLiteral = true;

            /*
             * When a command includes a word that is an expanded literal; for
             * example, {*}{1 2 3}, the parser performs that expansion
             * immediately, generating several TCL_TOKEN_SIMPLE_WORDs instead
             * of a single TCL_TOKEN_EXPAND_WORD that the Tcl_ParseCommand()
             * caller might have to expand. This notably makes it simpler for
             * those callers that wish to track line endings, such as those
             * that implement key parts of TIP 280.
             *
             * First check whether the thing to be expanded is a literal,
             * in the sense of being composed entirely of TCL_TOKEN_TEXT
             * tokens.
             */

            for ( i = 1; i <= token.numComponents; i++ )
            {
              if ( parse.getToken( wordIndex + i ).type != TCL_TOKEN_TEXT )//if (tokenPtr[i].type != TCL_TOKEN_TEXT) 
              {
                isLiteral = false;
                break;
              }
            }

            if ( isLiteral )
            {
              int elemCount = 0;
              FindElemResult code = null;
              bool nakedbs = false;
              int nextElem, listEnd;
              int elemStart = 0;

              /*
               * The word to be expanded is a literal, so determine the
               * boundaries of the literal string to be treated as a list
               * and expanded. That literal string starts at
               * tokenPtr[1].start, and includes all bytes up to, but not
               * including (tokenPtr[token.numComponents].start +
               * tokenPtr[token.numComponents].size)
               */

              //listEnd = ( tokenPtr[tokenPtr->numComponents].start +
              //  tokenPtr[tokenPtr->numComponents].size );
              listEnd = ( parse.getToken( wordIndex + token.numComponents ).script_index +
                parse.getToken( wordIndex + token.numComponents ).size ) - 1;
              nextElem = parse.getToken( wordIndex + token.numComponents ).script_index;//nextElem = tokenPtr[1].start;


              /*
               * Step through the literal string, parsing and counting list
               * elements.
               */

              string string_array = new string( token.script_array );
              while ( nextElem < listEnd )
              {
                int size;

                code = Util.findElement( null, string_array, nextElem, listEnd );
                //code = TclFindElement(NULL, nextElem, listEnd - nextElem,
                //  &elemStart, &nextElem, &size, &brace);
                if ( code == null )
                {
                  break;
                }
                if ( !code.brace )
                {
                  size = code.size;
                  elemStart = nextElem;
                  int s;

                  for ( s = elemStart; size > 0; s++, size-- )
                  {
                    if ( token.script_array[s] == '\\' )
                    {
                      nakedbs = true;
                      break;
                    }
                  }
                }
                elemCount++;
                nextElem = code.elemEnd;
              }

              if ( ( code == null ) || nakedbs )
              {
                /*
                 * Some  list element  could not  be parsed,  or contained
                 * naked  backslashes. This means  the literal  string was
                 * not  in fact  a  valid nor  canonical  list. Defer  the
                 * handling of  this to  compile/eval time, where  code is
                 * already  in place to  report the  "attempt to  expand a
                 * non-list" error or expand lists that require
                 * substitution.
                 */

                token.type = TCL_TOKEN_EXPAND_WORD;
              }
              else if ( elemCount == 0 )
              {
                /*
                 * We are expanding a literal empty list. This means that
                 * the expanding word completely disappears, leaving no
                 * word generated this pass through the loop. Adjust
                 * accounting appropriately.
                 */

                parse.numWords--;
                parse.numTokens = wordIndex;
              }
              else
              {
                /*
                 * Recalculate the number of Tcl_Tokens needed to store
                 * tokens representing the expanded list.
                 */

                int growthNeeded = wordIndex + 2 * elemCount
                  - parse.numTokens;
                parse.numWords += elemCount - 1;
                if ( growthNeeded > 0 )
                {
                  parse.expandTokenArray( growthNeeded );// TclGrowParseTokenArray( parse, growthNeeded );
                  token = parse.getToken( wordIndex );//&parsePtr->tokenPtr[wordIndex];
                }
                parse.numTokens = wordIndex + 2 * elemCount;


                /*
                 * Generate a TCL_TOKEN_SIMPLE_WORD token sequence for
                 * each element of the literal list we are expanding in
                 * place. Take care with the start and size fields of each
                 * token so they point to the right literal characters in
                 * the original script to represent the right expanded
                 * word value.
                 */

                nextElem = parse.getToken( wordIndex ).script_index;//tokenPtr[1].start;
                while ( token.script_array[nextElem] == ' ' )//isspace( UCHAR( *nextElem ) ) )
                {
                  nextElem++;
                }
                while ( nextElem < listEnd )
                {
                  token.type = TCL_TOKEN_SIMPLE_WORD;
                  token.numComponents = 1;
                  token.script_index = nextElem;

                  token = parse.getToken( ++wordIndex );// tokenPtr++;
                  token.type = TCL_TOKEN_TEXT;
                  token.numComponents = 0;
                  code = Util.findElement( null, string_array, nextElem, listEnd );
                  //TclFindElement(NULL, nextElem, listEnd - nextElem,
                  //  &(tokenPtr->start), &nextElem,
                  //  &(tokenPtr->size), NULL);
                  token.script_index = nextElem + ( code.brace ? 1 : 0 );
                  token.size = code.size;
                  nextElem = code.elemEnd;
                  if ( token.script_index + token.size == listEnd )
                  {
                    parse.getToken( wordIndex - 1 ).size = listEnd - parse.getToken( wordIndex - 1 ).script_index;//tokenPtr[-1].size = listEnd - tokenPtr[-1].start;
                  }
                  else
                  {
                    //tokenPtr[-1].size = tokenPtr->start
                    //  + tokenPtr->size - tokenPtr[-1].start;
                    parse.getToken( wordIndex - 1 ).size = token.script_index
                      + token.size - parse.getToken( wordIndex - 1 ).script_index;
                    if ( script_index + token.size < token.script_array.Length &&
                      ( token.script_array[script_index + token.size] == ' ' ) )
                      parse.getToken( wordIndex - 1 ).size += 1;
                    //  tokenPtr[-1].size += ( isspace( UCHAR(
                    //tokenPtr->start[tokenPtr->size] ) ) == 0 );
                  }

                  token = parse.getToken( ++wordIndex );// tokenPtr++;
                }
              }
            }
            else
            {
              /*
               * The word to be expanded is not a literal, so defer
               * expansion to compile/eval time by marking with a
               * TCL_TOKEN_EXPAND_WORD token.
               */

              token.type = TCL_TOKEN_EXPAND_WORD;
            }
          }
          else if ( ( token.numComponents == 1 ) && ( parse.getToken( wordIndex + 1 ).type == TCL_TOKEN_TEXT ) )
          {
            token.type = TCL_TOKEN_SIMPLE_WORD;
          }


          // Do two additional checks: (a) make sure we're really at the
          // end of a word (there might have been garbage left after a
          // quoted or braced word), and (b) check for the end of the
          // command.

          cur = script_array[script_index];
          type = ( ( cur > TYPE_MAX ) ? TYPE_NORMAL : typeTable[cur] );

          if ( type == TYPE_SPACE )
          {
            script_index++;
            continue;
          }
          else
          {
            // Backslash-newline (and any following white space) must be
            // treated as if it were a space character.

            if ( ( cur == '\\' ) && ( script_array[script_index + 1] == '\n' ) )
            {
              if ( ( script_index + 2 ) == parse.endIndex )
              {
                parse.incomplete = true;
              }
              bs = backslash( script_array, script_index );
              script_index = bs.nextIndex;
              continue;
            }
          }

          if ( ( type & terminators ) != 0 )
          {
            script_index++;
            break;
          }
          if ( script_index == parse.endIndex )
          {
            if ( nested && savedChar != ']' )
            {
              parse.incomplete = true;
              throw new TclException( interp, "missing close-bracket" );
            }
            break;
          }
          parse.termIndex = script_index;
          if ( script_array[script_index - 1] == '"' )
          {
            throw new TclException( interp, "extra characters after close-quote" );
          }
          else
          {
            throw new TclException( interp, "extra characters after close-brace" );
          }
        }
      }
      catch ( TclException e )
      {
        script_array[endIndex] = savedChar;
        if ( parse.commandStart < 0 )
        {
          parse.commandStart = saved_script_index;
        }
        parse.commandSize = parse.termIndex - parse.commandStart;
        parse.result = TCL.CompletionCode.ERROR;
        return parse;
      }

      script_array[endIndex] = savedChar;
      parse.commandSize = script_index - parse.commandStart;
      parse.result = TCL.CompletionCode.OK;
      return parse;
    }
Exemple #4
0
    public static TclParse parseVarName( Interp interp, char[] script_array, int script_index, int numBytes, TclParse parse, bool append )
    // Non-zero means append tokens to existing
    // information in parse; zero means ignore
    // existing tokens in parse and reinitialize
    // it. 
    {
      char cur;
      TclToken token, startToken;
      int endIndex, varIndex;

#if DEBUG
				System.Diagnostics.Debug.WriteLine();
				System.Diagnostics.Debug.WriteLine("Entered parseVarName()");
				System.Diagnostics.Debug.Write("now to parse var off the string \"");
				for (int k = script_index; k < script_array.Length; k++)
				{
					System.Diagnostics.Debug.Write(script_array[k]);
				}
				System.Diagnostics.Debug.WriteLine("\"");
#endif


      if ( numBytes >= 0 )
      {
        endIndex = script_index + numBytes;
      }
      else
      {
        endIndex = script_array.Length - 1;
      }
      if ( !append )
      {
        parse = new TclParse( interp, script_array, endIndex, null, -1 );
      }

      // Generate one token for the variable, an additional token for the
      // name, plus any number of additional tokens for the index, if
      // there is one.

      token = parse.getToken( parse.numTokens );
      token.type = TCL_TOKEN_VARIABLE;
      token.script_array = script_array;
      token.script_index = script_index;
      varIndex = parse.numTokens;
      parse.numTokens++;
      script_index++;
      if ( script_index >= endIndex )
      {
        // The dollar sign isn't followed by a variable name.
        // replace the TCL_TOKEN_VARIABLE token with a
        // TCL_TOKEN_TEXT token for the dollar sign.

        token.type = TCL_TOKEN_TEXT;
        token.size = 1;
        token.numComponents = 0;
        parse.result = TCL.CompletionCode.OK;
        return parse;
      }
      startToken = token;
      token = parse.getToken( parse.numTokens );

      // The name of the variable can have three forms:
      // 1. The $ sign is followed by an open curly brace.  Then 
      //    the variable name is everything up to the next close
      //    curly brace, and the variable is a scalar variable.
      // 2. The $ sign is not followed by an open curly brace.  Then
      //    the variable name is everything up to the next
      //    character that isn't a letter, digit, or underscore.
      //    :: sequences are also considered part of the variable
      //    name, in order to support namespaces. If the following
      //    character is an open parenthesis, then the information
      //    between parentheses is the array element name.
      // 3. The $ sign is followed by something that isn't a letter,
      //    digit, or underscore:  in this case, there is no variable
      //    name and the token is just "$".

      if ( script_array[script_index] == '{' )
      {
        System.Diagnostics.Debug.WriteLine( "parsing curley var name" );

        script_index++;
        token.type = TCL_TOKEN_TEXT;
        token.script_array = script_array;
        token.script_index = script_index;
        token.numComponents = 0;

        while ( true )
        {
          if ( script_index == endIndex )
          {
            if ( interp != null )
            {
              interp.setResult( "missing close-brace for variable name" );
            }
            parse.termIndex = token.script_index - 1;
            parse.incomplete = true;
            parse.result = TCL.CompletionCode.ERROR;
            return parse;
          }
          if ( script_array[script_index] == '}' )
          {
            break;
          }
          script_index++;
        }
        token.size = script_index - token.script_index;
        startToken.size = script_index - startToken.script_index;
        parse.numTokens++;
        script_index++;
      }
      else
      {
        System.Diagnostics.Debug.WriteLine( "parsing non curley var name" );

        token.type = TCL_TOKEN_TEXT;
        token.script_array = script_array;
        token.script_index = script_index;
        token.numComponents = 0;
        while ( script_index != endIndex )
        {
          cur = script_array[script_index];
          if ( ( System.Char.IsLetterOrDigit( cur ) ) || ( cur == '_' ) )
          {
            script_index++;
            continue;
          }
          if ( ( cur == ':' ) && ( ( ( script_index + 1 ) != endIndex ) && ( script_array[script_index + 1] == ':' ) ) )
          {
            script_index += 2;
            while ( ( script_index != endIndex ) && ( script_array[script_index] == ':' ) )
            {
              script_index++;
            }
            continue;
          }
          break;
        }
        token.size = script_index - token.script_index;
        if ( token.size == 0 )
        {
          // The dollar sign isn't followed by a variable name.
          // replace the TCL_TOKEN_VARIABLE token with a
          // TCL_TOKEN_TEXT token for the dollar sign.

          System.Diagnostics.Debug.WriteLine( "single $ with no var name found" );

          startToken.type = TCL_TOKEN_TEXT;
          startToken.size = 1;
          startToken.numComponents = 0;
          parse.result = TCL.CompletionCode.OK;
          return parse;
        }
        parse.numTokens++;
        if ( ( script_index != endIndex ) && ( script_array[script_index] == '(' ) )
        {
          // This is a reference to an array element.  Call
          // parseTokens recursively to parse the element name,
          // since it could contain any number of substitutions.

          System.Diagnostics.Debug.WriteLine( "parsing array element" );

          script_index++;
          parse = parseTokens( script_array, script_index, TYPE_CLOSE_PAREN, parse );
          if ( parse.result != TCL.CompletionCode.OK )
          {
            return parse;
          }
          if ( ( parse.termIndex == endIndex ) || ( parse.inString[parse.termIndex] != ')' ) )
          {
            if ( interp != null )
            {
              interp.setResult( "missing )" );
            }
            parse.termIndex = script_index - 1;
            parse.incomplete = true;
            parse.result = TCL.CompletionCode.ERROR;
            return parse;
          }
          script_index = parse.termIndex + 1;
        }
      }


#if DEBUG
				System.Diagnostics.Debug.WriteLine("default end parse case");
				System.Diagnostics.Debug.Write("var token is \"");
				for (int k = startToken.script_index; k < script_index; k++)
				{
					System.Diagnostics.Debug.Write(script_array[k]);
				}
				System.Diagnostics.Debug.WriteLine("\"");
#endif

      startToken.size = script_index - startToken.script_index;
      startToken.numComponents = parse.numTokens - ( varIndex + 1 );
      parse.result = TCL.CompletionCode.OK;
      return parse;
    }
Exemple #5
0
    public static TclParse parseCommand( Interp interp, char[] script_array, int script_index, int numBytes, string fileName, int lineNum, bool nested )
    // True means that this is a nested command:
    // close bracket should be considered
    // a command terminator.  If false, then close
    // bracket has no special meaning. 
    {

      char cur; //the char we are currently parsing
      int type; // Result returned by charType(src.charAt()). 
      TclToken token; // Pointer to token being filled in. 
      int wordIndex; // Index of word token for current word. 
      int level; // Nesting level of curly braces: gives
      // number of right braces we must find to
      // end word. 
      TclParse parse; // Return value to fill in with information
      // about the parsed command.
      int terminators; // charType() bits that indicate the end
      // of a command. 
      BackSlashResult bs; // Result of a call to backslash(...).
      int endIndex; // Index that points to the character after
      // the last character to be parsed.
      char savedChar; // To terminate the parsing correctly, the
      // character at endIndex is set to \0.  This
      // stores the value to return when finished.


      int saved_script_index = script_index; //save the original index


      int script_length = script_array.Length - 1;


      if ( numBytes < 0 )
      {
        numBytes = script_length - script_index;
      }
      endIndex = script_index + numBytes;
      if ( endIndex > script_length )
      {
        endIndex = script_length;
      }

      savedChar = script_array[endIndex];
      script_array[endIndex] = '\x0000';

      parse = new TclParse( interp, script_array, endIndex, fileName, lineNum );

      if ( nested )
      {
        terminators = TYPE_COMMAND_END | TYPE_CLOSE_BRACK;
      }
      else
      {
        terminators = TYPE_COMMAND_END;
      }

      // Parse any leading space and comments before the first word of the
      // command.


      try
      {

        while ( true )
        {

          cur = script_array[script_index];

          while ( ( ( cur <= TYPE_MAX ) && ( typeTable[cur] == TYPE_SPACE ) ) || ( cur == '\n' ) )
          {
            cur = script_array[++script_index];
          }

          if ( ( cur == '\\' ) && ( script_array[script_index + 1] == '\n' ) )
          {

            // Skip backslash-newline sequence: it should be treated
            // just like white space.

            if ( ( script_index + 2 ) == parse.endIndex )
            {
              parse.incomplete = true;
            }

            //this will add 2 to the offset and return to the top
            //of the while(true) loop which will get the next cur

            script_index += 2;
            continue;
          }

          // If we have found the start of a command goto the word parsing loop
          if ( cur != '#' )
          {
            break;
          }

          // Record the index where the comment starts
          if ( parse.commentStart < 0 )
          {
            parse.commentStart = script_index;
          }

          while ( true )
          {
            cur = script_array[script_index];
            if ( script_index == parse.endIndex )
            {
              if ( nested )
                parse.incomplete = true;
              parse.commentSize = script_index - parse.commentStart;
              break;
            }
            else if ( cur == '\\' )
            {
              if ( ( script_array[script_index + 1] == '\n' ) && ( ( script_index + 2 ) == parse.endIndex ) )
              {
                parse.incomplete = true;
              }
              bs = backslash( script_array, script_index );
              script_index = bs.nextIndex;
            }
            else if ( cur == '\n' )
            {
              script_index++;
              parse.commentSize = script_index - parse.commentStart;
              break;
            }
            else
            {
              script_index++;
            }
          }
        }



        // The following loop parses the words of the command, one word
        // in each iteration through the loop.

        parse.commandStart = script_index;

        while ( true )
        {

          // Create the token for  the word.
          wordIndex = parse.numTokens;

          token = parse.getToken( wordIndex );
          token.type = TCL_TOKEN_WORD;

          // Skip white space before the word. Also skip a backslash-newline
          // sequence: it should be treated just like white space.


          while ( true )
          {
            cur = script_array[script_index];
            type = ( ( cur > TYPE_MAX ) ? TYPE_NORMAL : typeTable[cur] );

            if ( type == TYPE_SPACE )
            {
              script_index++;
              continue;
            }
            else if ( ( cur == '\\' ) && ( script_array[script_index + 1] == '\n' ) )
            {
              if ( ( script_index + 2 ) == parse.endIndex )
              {
                parse.incomplete = true;
              }
              bs = backslash( script_array, script_index );
              script_index = bs.nextIndex;
              continue;
            }
            break;
          }

          if ( ( type & terminators ) != 0 )
          {
            script_index++;
            break;
          }

          if ( script_index == parse.endIndex )
          {
            if ( nested && savedChar != ']' )
            {
              parse.incomplete = true;
              throw new TclException( interp, "missing close-bracket" );
            }
            break;
          }

          token.script_array = script_array;
          token.script_index = script_index;

          parse.numTokens++;
          parse.numWords++;


          // At this point the word can have one of three forms: something
          // enclosed in quotes, something enclosed in braces, or an
          // unquoted word (anything else).

          cur = script_array[script_index];

          if ( cur == '"' )
          {
            script_index++;
            parse = parseTokens( script_array, script_index, TYPE_QUOTE, parse );
            if ( parse.result != TCL.CompletionCode.OK )
            {
              throw new TclException( parse.result );
            }
            if ( parse.inString[parse.termIndex] != '"' )
            {
              parse.termIndex = script_index - 1;
              parse.incomplete = true;
              throw new TclException( parse.interp, "missing \"" );
            }
            script_index = parse.termIndex + 1;
          }
          else if ( cur == '{' )
          {
            // Find the matching right brace that terminates the word,
            // then generate a single token for everything between the
            // braces.

            script_index++;
            token = parse.getToken( parse.numTokens );
            token.type = TCL_TOKEN_TEXT;
            token.script_array = script_array;
            token.script_index = script_index;
            token.numComponents = 0;
            level = 1;
            while ( true )
            {
              cur = script_array[script_index];

              // get the current char in the array and lookup its type
              while ( ( ( cur > TYPE_MAX ) ? TYPE_NORMAL : typeTable[cur] ) == TYPE_NORMAL )
              {
                cur = script_array[++script_index];
              }
              if ( script_array[script_index] == '}' )
              {
                level--;
                if ( level == 0 )
                {
                  break;
                }
                script_index++;
              }
              else if ( script_array[script_index] == '{' )
              {
                level++;
                script_index++;
              }
              else if ( script_array[script_index] == '\\' )
              {
                bs = backslash( script_array, script_index );
                if ( script_array[script_index + 1] == '\n' )
                {
                  // A backslash-newline sequence requires special
                  // treatment: it must be collapsed, even inside
                  // braces, so we have to split the word into
                  // multiple tokens so that the backslash-newline
                  // can be represented explicitly.

                  if ( ( script_index + 2 ) == parse.endIndex )
                  {
                    parse.incomplete = true;
                  }
                  token.size = script_index - token.script_index;
                  if ( token.size != 0 )
                  {
                    parse.numTokens++;
                  }
                  token = parse.getToken( parse.numTokens );
                  token.type = TCL_TOKEN_BS;
                  token.script_array = script_array;
                  token.script_index = script_index;
                  token.size = bs.nextIndex - script_index;
                  token.numComponents = 0;
                  parse.numTokens++;
                  script_index = bs.nextIndex;
                  token = parse.getToken( parse.numTokens );
                  token.type = TCL_TOKEN_TEXT;
                  token.script_array = script_array;
                  token.script_index = script_index;
                  token.numComponents = 0;
                }
                else
                {
                  script_index = bs.nextIndex;
                }
              }
              else if ( script_index == parse.endIndex )
              {
                parse.termIndex = parse.getToken( wordIndex ).script_index;
                parse.incomplete = true;
                throw new TclException( interp, "missing close-brace" );
              }
              else
              {
                script_index++;
              }
            }
            if ( ( script_index != token.script_index ) || ( parse.numTokens == ( wordIndex + 1 ) ) )
            {
              token.size = script_index - token.script_index;
              parse.numTokens++;
            }
            script_index++;
          }
          else
          {
            // This is an unquoted word.  Call parseTokens and let it do
            // all of the work.

            parse = parseTokens( script_array, script_index, TYPE_SPACE | terminators, parse );
            if ( parse.result != TCL.CompletionCode.OK )
            {
              throw new TclException( parse.result );
            }
            script_index = parse.termIndex;
          }

          // Finish filling in the token for the word and check for the
          // special case of a word consisting of a single range of
          // literal text.

          token = parse.getToken( wordIndex );
          token.size = script_index - token.script_index;
          token.numComponents = parse.numTokens - ( wordIndex + 1 );
          if ( ( token.numComponents == 1 ) && ( parse.getToken( wordIndex + 1 ).type == TCL_TOKEN_TEXT ) )
          {
            token.type = TCL_TOKEN_SIMPLE_WORD;
          }

          // Do two additional checks: (a) make sure we're really at the
          // end of a word (there might have been garbage left after a
          // quoted or braced word), and (b) check for the end of the
          // command.


          cur = script_array[script_index];
          type = ( ( cur > TYPE_MAX ) ? TYPE_NORMAL : typeTable[cur] );

          if ( type == TYPE_SPACE )
          {
            script_index++;
            continue;
          }
          else
          {
            // Backslash-newline (and any following white space) must be
            // treated as if it were a space character.

            if ( ( cur == '\\' ) && ( script_array[script_index + 1] == '\n' ) )
            {
              if ( ( script_index + 2 ) == parse.endIndex )
              {
                parse.incomplete = true;
              }
              bs = backslash( script_array, script_index );
              script_index = bs.nextIndex;
              continue;
            }
          }

          if ( ( type & terminators ) != 0 )
          {
            script_index++;
            break;
          }
          if ( script_index == parse.endIndex )
          {
            if ( nested && savedChar != ']' )
            {
              parse.incomplete = true;
              throw new TclException( interp, "missing close-bracket" );
            }
            break;
          }
          parse.termIndex = script_index;
          if ( script_array[script_index - 1] == '"' )
          {
            throw new TclException( interp, "extra characters after close-quote" );
          }
          else
          {
            throw new TclException( interp, "extra characters after close-brace" );
          }
        }
      }
      catch ( TclException e )
      {
        script_array[endIndex] = savedChar;
        if ( parse.commandStart < 0 )
        {
          parse.commandStart = saved_script_index;
        }
        parse.commandSize = parse.termIndex - parse.commandStart;
        parse.result = TCL.CompletionCode.ERROR;
        return parse;
      }

      script_array[endIndex] = savedChar;
      parse.commandSize = script_index - parse.commandStart;
      parse.result = TCL.CompletionCode.OK;
      return parse;
    }
        internal static ParseResult parseQuotes(Interp interp, string inString, int index, int length)
        {
            TclObject   obj;
            TclParse    parse = null;
            TclToken    token;
            CharPointer script;

            try
            {
                script       = new CharPointer(inString);
                script.index = index;

                parse = new TclParse(interp, script.array, length, null, 0);

                System.Diagnostics.Debug.WriteLine("string is \"" + inString + "\"");
                System.Diagnostics.Debug.WriteLine("script.array is \"" + new string( script.array ) + "\"");

                System.Diagnostics.Debug.WriteLine("index is " + index);
                System.Diagnostics.Debug.WriteLine("length is " + length);

                System.Diagnostics.Debug.WriteLine("parse.endIndex is " + parse.endIndex);


                parse.commandStart = script.index;
                token              = parse.getToken(0);
                token.type         = Parser.TCL_TOKEN_WORD;
                token.script_array = script.array;
                token.script_index = script.index;
                parse.numTokens++;
                parse.numWords++;
                parse = Parser.parseTokens(script.array, script.index, Parser.TYPE_QUOTE, parse);

                // Check for the error condition where the parse did not end on
                // a '"' char. Is this happened raise an error.

                if (script.array[parse.termIndex] != '"')
                {
                    throw new TclException(interp, "missing \"");
                }

                // if there was no error then parsing will continue after the
                // last char that was parsed from the string

                script.index = parse.termIndex + 1;

                // Finish filling in the token for the word and check for the
                // special case of a word consisting of a single range of
                // literal text.

                token               = parse.getToken(0);
                token.size          = script.index - token.script_index;
                token.numComponents = parse.numTokens - 1;
                if ((token.numComponents == 1) && (parse.getToken(1).type == Parser.TCL_TOKEN_TEXT))
                {
                    token.type = Parser.TCL_TOKEN_SIMPLE_WORD;
                }
                parse.commandSize = script.index - parse.commandStart;
                if (parse.numTokens > 0)
                {
                    obj = Parser.evalTokens(interp, parse.tokenList, 1, parse.numTokens - 1);
                }
                else
                {
                    throw new TclRuntimeError("parseQuotes error: null obj result");
                }
            }
            finally
            {
                parse.release();
            }

            return(new ParseResult(obj, script.index));
        }