All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.javacc.parser.CodeGenerator Maven / Gradle / Ivy

There is a newer version: 4.1.5
Show newest version
// Copyright 2011 Google Inc. All Rights Reserved.
// Author: [email protected] (Sreeni Viswanadha)

package org.javacc.parser;

import static org.javacc.parser.JavaCCGlobals.addUnicodeEscapes;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

public class CodeGenerator
{
  protected StringBuffer mainBuffer = new StringBuffer ();
  protected StringBuffer includeBuffer = new StringBuffer ();
  protected StringBuffer staticsBuffer = new StringBuffer ();
  protected StringBuffer outputBuffer = mainBuffer;

  public void genStringLiteralArrayCPP (final String varName, final String [] arr)
  {
    // First generate char array vars
    for (int i = 0; i < arr.length; i++)
    {
      genCodeLine ("static const JAVACC_CHAR_TYPE " + varName + "_arr_" + i + "[] = ");
      genStringLiteralInCPP (arr[i]);
      genCodeLine (";");
    }

    genCodeLine ("static const JAVACC_STRING_TYPE " + varName + "[] = {");
    for (int i = 0; i < arr.length; i++)
    {
      genCodeLine (varName + "_arr_" + i + ", ");
    }
    genCodeLine ("};");
  }

  public void genStringLiteralInCPP (final String s)
  {
    // String literals in CPP become char arrays
    outputBuffer.append ("{");
    for (int i = 0; i < s.length (); i++)
    {
      outputBuffer.append ("0x" + Integer.toHexString (s.charAt (i)) + ", ");
    }
    outputBuffer.append ("0}");
  }

  public void genCodeLine (final Object... code)
  {
    genCode (code);
    genCode ("\n");
  }

  public void genCode (final Object... code)
  {
    for (final Object s : code)
    {
      outputBuffer.append (s);
    }
  }

  public void saveOutput (final String fileName)
  {
    if (!isJavaLanguage ())
    {
      final String incfileName = fileName.replace (".cc", ".h");
      includeBuffer.insert (0, "#define " + new File (incfileName).getName ().replace ('.', '_').toUpperCase () + "\n");
      includeBuffer.insert (0, "#ifndef " + new File (incfileName).getName ().replace ('.', '_').toUpperCase () + "\n");

      // dump the statics into the main file with the code.
      mainBuffer.insert (0, staticsBuffer);

      // Finally enclose the whole thing in the namespace, if specified.
      if (Options.stringValue (Options.USEROPTION_CPP_NAMESPACE).length () > 0)
      {
        mainBuffer.insert (0, "namespace " + Options.stringValue ("NAMESPACE_OPEN") + "\n");
        mainBuffer.append (Options.stringValue ("NAMESPACE_CLOSE") + "\n");
        includeBuffer.append (Options.stringValue ("NAMESPACE_CLOSE") + "\n");
      }

      mainBuffer.insert (0, "#include \"" + incfileName + "\"\n");
      includeBuffer.append ("#endif\n");
      saveOutput (incfileName, includeBuffer);
    }

    mainBuffer.insert (0, "/* " + new File (fileName).getName () + " */\n");
    saveOutput (fileName, mainBuffer);
  }

  private static boolean isHexDigit (final char c)
  {
    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
  }

  // HACK
  private void fixupLongLiterals (final StringBuffer sb)
  {
    for (int i = 0; i < sb.length () - 1; i++)
    {
      final int beg = i;
      final char c1 = sb.charAt (i);
      final char c2 = sb.charAt (i + 1);
      if (Character.isDigit (c1) || (c1 == '0' && c2 == 'x'))
      {
        i += c1 == '0' ? 2 : 1;
        while (isHexDigit (sb.charAt (i)))
          i++;
        if (sb.charAt (i) == 'L')
        {
          sb.insert (i, "UL");
        }
        i++;
      }
    }
  }

  public void saveOutput (final String fileName, final StringBuffer sb)
  {
    PrintWriter fw = null;
    if (!isJavaLanguage ())
    {
      fixupLongLiterals (sb);
    }
    try
    {
      final File tmp = new File (fileName);
      fw = new PrintWriter (new BufferedWriter (new FileWriter (tmp), 8092));

      fw.print (sb.toString ());
    }
    catch (final IOException ioe)
    {
      JavaCCErrors.fatal ("Could not create output file: " + fileName);
    }
    finally
    {
      if (fw != null)
      {
        fw.close ();
      }
    }
  }

  protected int cline, ccol;

  protected void printTokenSetup (final Token t)
  {
    Token tt = t;

    while (tt.specialToken != null)
    {
      tt = tt.specialToken;
    }

    cline = tt.beginLine;
    ccol = tt.beginColumn;
  }

  protected void printTokenList (final List list)
  {
    Token t = null;
    for (final java.util.Iterator it = list.iterator (); it.hasNext ();)
    {
      t = (Token) it.next ();
      printToken (t);
    }

    if (t != null)
      printTrailingComments (t);
  }

  protected void printTokenOnly (final Token t)
  {
    genCode (getStringForTokenOnly (t));
  }

  protected String getStringForTokenOnly (final Token t)
  {
    String retval = "";
    for (; cline < t.beginLine; cline++)
    {
      retval += "\n";
      ccol = 1;
    }
    for (; ccol < t.beginColumn; ccol++)
    {
      retval += " ";
    }
    if (t.kind == JavaCCParserConstants.STRING_LITERAL || t.kind == JavaCCParserConstants.CHARACTER_LITERAL)
      retval += addUnicodeEscapes (t.image);
    else
      retval += t.image;
    cline = t.endLine;
    ccol = t.endColumn + 1;
    if (t.image.length () > 0)
    {
      final char last = t.image.charAt (t.image.length () - 1);
      if (last == '\n' || last == '\r')
      {
        cline++;
        ccol = 1;
      }
    }

    return retval;
  }

  protected void printToken (final Token t)
  {
    genCode (getStringToPrint (t));
  }

  protected String getStringToPrint (final Token t)
  {
    String retval = "";
    Token tt = t.specialToken;
    if (tt != null)
    {
      while (tt.specialToken != null)
        tt = tt.specialToken;
      while (tt != null)
      {
        retval += getStringForTokenOnly (tt);
        tt = tt.next;
      }
    }

    return retval + getStringForTokenOnly (t);
  }

  protected void printLeadingComments (final Token t)
  {
    genCode (getLeadingComments (t));
  }

  protected String getLeadingComments (final Token t)
  {
    String retval = "";
    if (t.specialToken == null)
      return retval;
    Token tt = t.specialToken;
    while (tt.specialToken != null)
      tt = tt.specialToken;
    while (tt != null)
    {
      retval += getStringForTokenOnly (tt);
      tt = tt.next;
    }
    if (ccol != 1 && cline != t.beginLine)
    {
      retval += "\n";
      cline++;
      ccol = 1;
    }

    return retval;
  }

  protected void printTrailingComments (final Token t)
  {
    outputBuffer.append (getTrailingComments (t));
  }

  protected String getTrailingComments (final Token t)
  {
    if (t.next == null)
      return "";
    return getLeadingComments (t.next);
  }

  /**
   * for testing
   */
  public String getGeneratedCode ()
  {
    return outputBuffer.toString () + "\n";
  }

  /**
   * Generate annotation. @XX syntax for java, comments in C++
   */
  public void genAnnotation (final String ann)
  {
    if (Options.isOutputLanguageJava ())
    {
      genCode ("@" + ann);
    }
    else
      if (Options.getOutputLanguage ().equals (Options.OUTPUT_LANGUAGE__CPP))
      { // For now, it's only C++ for now
        genCode ("/*" + ann + "*/");
      }
      else
      {
        throw new RuntimeException ("Unknown language : " + Options.getOutputLanguage ());
      }
  }

  /**
   * Generate a modifier
   */
  public void genModifier (final String mod)
  {
    final String origMod = mod.toLowerCase ();
    if (isJavaLanguage ())
    {
      genCode (mod);
    }
    else
    { // For now, it's only C++ for now
      if (origMod.equals ("public") || origMod.equals ("private"))
      {
        genCode (origMod + ": ");
      }
      // we don't care about other mods for now.
    }
  }

  /**
   * Generate a class with a given name, an array of superclass and another
   * array of super interfaes
   */
  public void genClassStart (final String mod,
                             final String name,
                             final String [] superClasses,
                             final String [] superInterfaces)
  {
    final boolean isJavaLanguage = isJavaLanguage ();
    if (isJavaLanguage && mod != null)
    {
      genModifier (mod);
    }
    genCode ("class " + name);
    if (isJavaLanguage)
    {
      if (superClasses.length == 1 && superClasses[0] != null)
      {
        genCode (" extends " + superClasses[0]);
      }
      if (superInterfaces.length != 0)
      {
        genCode (" implements ");
      }
    }
    else
    {
      if (superClasses.length > 0 || superInterfaces.length > 0)
      {
        genCode (" : ");
      }

      genCommaSeperatedString (superClasses);
    }

    genCommaSeperatedString (superInterfaces);
    genCodeLine (" {");
    if (Options.getOutputLanguage ().equals (Options.OUTPUT_LANGUAGE__CPP))
    {
      genCodeLine ("   public:");
    }
  }

  private void genCommaSeperatedString (final String [] strings)
  {
    for (int i = 0; i < strings.length; i++)
    {
      if (i > 0)
      {
        genCode (", ");
      }

      genCode (strings[i]);
    }
  }

  protected boolean isJavaLanguage ()
  {
    // TODO :: CBA -- Require Unification of output language specific processing
    // into a single Enum class
    return Options.isOutputLanguageJava ();
  }

  public void switchToMainFile ()
  {
    outputBuffer = mainBuffer;
  }

  public void switchToStaticsFile ()
  {
    if (!isJavaLanguage ())
    {
      outputBuffer = staticsBuffer;
    }
  }

  public void switchToIncludeFile ()
  {
    if (!isJavaLanguage ())
    {
      outputBuffer = includeBuffer;
    }
  }

  public void generateMethodDefHeader (final String modsAndRetType, final String className, final String nameAndParams)
  {
    generateMethodDefHeader (modsAndRetType, className, nameAndParams, null);
  }

  public void generateMethodDefHeader (String modsAndRetType,
                                       final String className,
                                       final String nameAndParams,
                                       final String exceptions)
  {
    // for C++, we generate the signature in the header file and body in main
    // file
    if (isJavaLanguage ())
    {
      genCode (modsAndRetType + " " + nameAndParams);
      if (exceptions != null)
      {
        genCode (" throws " + exceptions);
      }
      genCodeLine ("");
    }
    else
    {
      includeBuffer.append ("\n" + modsAndRetType + " " + nameAndParams);
      // if (exceptions != null)
      // includeBuffer.append(" throw(" + exceptions + ")");
      includeBuffer.append (";\n");

      int i = modsAndRetType.lastIndexOf (':');
      if (i >= 0)
        modsAndRetType = modsAndRetType.substring (i + 1);

      i = modsAndRetType.lastIndexOf ("virtual");
      if (i >= 0)
        modsAndRetType = modsAndRetType.substring (i + "virtual".length ());

      mainBuffer.append ("\n" + modsAndRetType + " " + getClassQualifier (className) + nameAndParams);
      // if (exceptions != null)
      // mainBuffer.append(" throw( " + exceptions + ")");
      switchToMainFile ();
    }
  }

  protected String getClassQualifier (final String className)
  {
    return className == null ? "" : className + "::";
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy