⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 preprocessor.java

📁 外国人写的c#语法解析器
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
              {
                skip = SKIP_NONE;
                break;
              }
            }
            break;
          }
          default:
          {
            reportError("Unexpected #else preprocessor directive found.");
          }
        }
        break;
      }
      case ELIF:
      {
        Integer pendingState = (Integer) pendingStates.pop();
        // See what the state was, which opened this conditional branch.
        switch (pendingState.intValue())
        {
          case IFDEF:
          case IFNDEF:
          case IF:
          case ELIF:
          {
            pendingStates.push(ELIF_DIRECTIVE);
            
            // If the parent condition already was skipping then continue that.
            // If we are in a subbranch (elif branch), which is currently skipping then continue that.
            // If the previous condition was met then start skipping the entire branch that follows now.
            // And finally if the previous condition was not met then check here again for the current condition.
            if ((skip != SKIP_PARENT) && (skip != SKIP_SUBTREE))
            {
              // If currently lines are not skipped then the previous condition was met and
              // we have to skip everything from now on until the #endif that belongs to the condition starter.
              if (skip == SKIP_NONE)
              {
                skip = SKIP_SUBTREE;
              }
              else
              {
                boolean condition = evaluateBooleanExpression(macroTable.expandMacros(parts[1]));
                if (condition)
                  skip = SKIP_NONE;
              }
            }
            break;
          }
          default:
          {
            reportError("Unexpected #elif preprocessor directive found.");
          }
        }
        break;
      }
      case ENDIF:
      {
        Integer pendingState = (Integer) pendingStates.pop();
        Integer lastSkipMode = (Integer) skipFlags.pop();
        skip = lastSkipMode.intValue();
        // See what the state was, which opened this conditional branch.
        switch (pendingState.intValue())
        {
          case IF:
          case IFDEF:
          case IFNDEF:
          case ELIF:
          case ELSE:
          {
            // Return to parent mode.
            break;
          }
          default:
          {
            reportError("Unexpected #endif preprocessor directive found.");
          }
        }
        break;
      }
    }
    
    return result;
  }

  //------------------------------------------------------------------------------------------------

  /**
   * Handles an include directive by loading the given file and creating a new (nested) instance
   * of the preprocessor.
   * 
   * @param string Contains the rest of the #include line, which contains the file name.
   * @return <b>true</b> if a new preprocessor was set up, otherwise <b>false</b>.
   */
  private boolean processInclude(String filename) throws FileNotFoundException, IOException
  {
    boolean foundError = false;
    // Filenames must be given either quoted or enclosed in angles. We'll be tolerant by ignoring
    // everything, which comes after the file name.
    int quote = filename.indexOf('"');
    if (quote > -1)
    {
      // File name in quotes.
      int unquote = filename.indexOf('"', quote + 1);
      if (unquote == -1)
      {
        reportError("Invalid include statement.");
        foundError = true;
      }
      filename = filename.substring(quote + 1, unquote);
    }
    else
    {
      int leftAngle = filename.indexOf("<");
      if (leftAngle > -1)
      {
        // File name in angles.
        int rightAngle = filename.indexOf('>', leftAngle + 1);
        if (rightAngle == -1)
        {
          reportError("Invalid include statement.");
          foundError = true;
        }
        filename = filename.substring(leftAngle + 1, rightAngle);
      }
      else
      {
        reportError("Invalid include statement.");
        foundError = true;
      }
    }
    
    if (!foundError)
      return includeFile(filename);
    else
      return false;
  }

  //------------------------------------------------------------------------------------------------

  /**
   * Processes a #pragma directive. It particularly handles #pragma once and #pragma message. 
   * Everything else ist simply passed through to the output.
   * 
   * @param parts The directive line split into two parts ("pragma" and the rest).
   */
  private void processPragma(String[] parts) throws IOException
  {
    // MSDN states the resource compile does not support the pragma directive except for
    // pragma code_page. In header files also pragma once can appear (which is handled here).
    // But otherwise no more directives are supposedly supported. I wished the documentation
    // would keep up with the reality.
    if (parts.length < 2)
      reportError("Malformed pragma directive.");
    else
    {
      String pragma = parts[1].trim();
      if (pragma.equalsIgnoreCase("once"))
        processedIncludes.put(inputState.getFilename(), null);
      else
        if (pragma.startsWith("message"))
        {
          int start = pragma.indexOf('"');
          int stop = pragma.lastIndexOf('"');
          if (start > -1 && stop > -1)
            reportInfo(pragma.substring(start + 1, stop));
          else
            reportError("Invalid pragma message format.");
        }
        else
          if (pragma.startsWith("code_page"))
          {
            // TODO: Handle code page change.
          }
      // Ignore any other #pragma directive.
    }
  }

  //------------------------------------------------------------------------------------------------

  /**
   * Called if an #undef directive was found. Get the identifier and remove it from the symbol table.
   * 
   * @param definition Input containing the identifier.
   */
  private void processUndef(String definition)
  {
    String[] parts = definition.split(WHITESPACES, 2);
    if (parts.length == 0)
      reportError("Invalid #undef directive found.");
    else
    {
      String symbol = parts[0].trim();
      macroTable.undefineMacro(symbol);
    }
  }

  //------------------------------------------------------------------------------------------------

  /**
   * Scans the given string for comments and removes them. If the line contains a multiline comment
   * start but no end then the private field inMulitlineComment is set to true to tell the caller
   * how to proceed with following lines.
   * 
   * @param line The input line to process.
   * @return The cleaned up string without comments. Whitespaces at both ends are removed as well.
   */
  private String removeComments(String line) throws IOException
  {
    StringBuffer buffer = new StringBuffer(line);
    
    for (int i = 0; i < buffer.length(); i++)
    {
      switch (buffer.charAt(i))
      {
        case '/': // Potential comment start.
          // There must be at least one more character to have a comment start.
          if (i + 1 < buffer.length())
          {
            switch (buffer.charAt(i + 1))
            {
              case '/': // Single line comment found. Replace the comment by one space character.
                buffer.replace(i, buffer.length(), " ");
                break;
              case '*': // Multi line comment found. Scan for end.
                int commentEnd = buffer.indexOf("*/", i + 2);
                
                if (commentEnd > -1)
                  buffer.replace(i, commentEnd + 2, " ");
                else
                {
                  // The comment does not end on this line. Replace what we have by a space char
                  // and tell the caller about the open comment.
                  inMultilineComment = true;
                  buffer.replace(i, buffer.length(), " ");
                }
                break;
            }
          }
          break;
        case '"': // String start found. Search for its end before scanning further for comments.
          int stringEnd = buffer.indexOf("\"", i + 1);
          
          // If we did not find a string end delimiter then the source is syntactically wrong.
          if (stringEnd == -1)
          {
            i = buffer.length();
            reportError("Unterminated string found.");
          }
          else
            i = stringEnd;
          break;
      }
    }
    return buffer.toString().trim();
  }

  //------------------------------------------------------------------------------------------------

  /**
   * Splits the given line into the directive string and the rest.
   * 
   * @param line The line to split.
   */
  private String[] splitDirective(String line)
  {
    // Remove the leading number sign and split the rest into two parts of which the first
    // one is the textual form of the directive.
    int i = 1;
    
    // Skip white spaces between number sign and directive.
    while (i < line.length() && ((line.charAt(i) == ' ') || (line.charAt(i) == '\t')))
      i++;
    int nonWhitespaceStart = i;
    while (i < line.length())
    {
      // Stop scanning if there is a character not in the ranges 'a'..'z' or 'A'..'Z'.
      char letter = line.charAt(i);
      if (!((letter >= 'a') && (letter <= 'z') || (letter >= 'A') && (letter <= 'Z')))
        break;
      i++;
    }
    String[] values = new String[2];
    values[0] = line.substring(nonWhitespaceStart, i);
    values[1] = line.substring(i, line.length());
    
    return values;
  }

  //------------------------------------------------------------------------------------------------
  
  protected void doEvent(int event, String message, boolean addFileInfo)
  {
    switch (event)
    {
      case IParseEventListener.PANIC:
      case IParseEventListener.ERROR:
      {
        hadErrors = true;
        break;
      }
      case IParseEventListener.WARNING:
      {
        hadWarnings = true;
        break;
      }
    }
    
    if (addFileInfo)
    {
      message = MessageFormat.format(
        "{0}: [line {1}] {2}", 
        new Object[] 
        {
          inputState.getFullFilename(),
          new Integer(inputState.getLine()),
          message
        }
      );
    }
    
    for (int i = 0; i < listeners.size(); i++)
    {
      IParseEventListener listener = (IParseEventListener)listeners.get(i);
      listener.handleEvent(event, message);
    }
  }
  
  //------------------------------------------------------------------------------------------------

  /**
   * This method processes uncoditional input and returns when a non-preprocessor line was found.
   * 
   * @return The line, which caused the abort of unconditional input processing.
   * 
   * @throws IOException
   */
  protected String processUnconditionalInput() throws IOException
  {
    // Note: Comments are handled here because we have to make sure we do not consider outcommented
    //       preprocessor directives. Single line and multi line comments are converted to one space
    //       character each, so the output does not contain comments anymore (which somewhat 
    //       simplifies the following parser stage).
    String line = null;
    boolean canReturn = false;
    do
    {
      line = readLine();
      if (line == null)
        break;
  
      // Now that the string is cleaned-up we can start processing directives.
      if (line.startsWith("#"))
      {
        canReturn = processDirective(line);
        if (canReturn)
          line = "";
      }
      else
      {
        // No preprocessor directive in this line, so return it to the caller if it is not empty.
        if ((skip == SKIP_NONE) && !skipNonPPLines)
        {
          line = macroTable.expandMacros(line);
          if (line.length() > 0)
            canReturn = true;
        }
      }
    }
    while (!canReturn);
    
    return line;
  }

  //------------------------------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -