options {
  STATIC = false;
  JAVA_UNICODE_ESCAPE = true;
}

PARSER_BEGIN(Parser)
import edu.neu.ccs.demeter.dj.*;
import java.lang.reflect.*;
import edu.neu.ccs.demeter.*;
public class Parser { 
  // oit is uugly.  Why isn't there a Character.valueOf(String)? 
  static char unescapifyChar(String s) { 
    char c = s.charAt(0); 
    if (c == '\\') { 
      switch (s.charAt(1)) { 
      case 'n': c = '\n'; break; 
      case 't': c = '\t'; break; 
      case 'b': c = '\b'; break; 
      case 'r': c = '\r'; break; 
      case 'f': c = '\f'; break; 
      case '\\': c = '\\'; break; 
      case '\'': c = '\''; break; 
      case '\"': c = '\"'; break; 
      default: 
       c = (char) Integer.parseInt(s.substring(1, s.length()), 8); 
       break; 
      } 
    } 
    return c; 
  } 
  // Even uglier... 
  static String unescapify(String s) { 
    char str[] = new char[s.length()]; 
    int i = 0, o = 0; 
    while (i < s.length()) { 
      char c = s.charAt(i++); 
      if (c == '\\') { 
       int j = i + 1; 
       while (j < s.length() && 
              Character.digit(s.charAt(j), 8) != -1) { 
         j++; 
       } 
       c = unescapifyChar(s.substring(i-1, j)); 
       i = j; 
      } 
      str[o++] = c; 
    } 
    return String.valueOf(str, 0, o); 
  } 
} 

PARSER_END(Parser)

FileSystem _FileSystem() : {
  FileSystem it = null;
  CompoundFile _root;
} {
  { it=new FileSystem(); }
  _root=_CompoundFile() { it.set_root(_root); }
  <EOF>
  { return it; }
}

File _File() : {
  File it = null;
} {
  ( it=_SimpleFile() | it=_CompoundFile() )
  { return it; }
}

void common_File(File it) : {
  FileName _f;
} {
  _f=_FileName() { it.set_f(_f); }
  { }
}

SimpleFile _SimpleFile() : {
  SimpleFile it = null;
} {
  { it=new SimpleFile(); }
  "simple"  common_File(it)
  { return it; }
}

CompoundFile _CompoundFile() : {
  CompoundFile it = null;
  File_PList _contents;
  CompoundFile _parent;
} {
  { it=new CompoundFile(); }
  "compound"  _contents=_File_PList() { it.set_contents(_contents); }
  [  _parent=_CompoundFile() { it.set_parent(_parent); }  ]
  common_File(it)
  { return it; }
}

Commands _Commands() : {
  Commands it = null;
  Command_List _command_list;
} {
  { it=new Commands(); }
  _command_list=_Command_List() { it.set_command_list(_command_list); }
  <EOF>
  { return it; }
}

Command _Command() : {
  Command it = null;
} {
  ( it=_Simple() )
  { return it; }
}

void common_Command(Command it) : {
} {
  { }
}

Simple _Simple() : {
  Simple it = null;
} {
  ( it=_MakeDirectory() | it=_ChangeDirectoryUp() | it=_ChangeDirectoryDown() | it=_RecursiveCopy() | it=_DiskUsage() | it=_Find() | it=_Echo() | it=_SymbolicLink() | it=_RemoveDirectory() | it=_CreateEmptyFile() | it=_RemoveFile() )
  { return it; }
}

void common_Simple(Simple it) : {
} {
  common_Command(it)
  { }
}

MakeDirectory _MakeDirectory() : {
  MakeDirectory it = null;
  DirectoryName _directoryname;
} {
  { it=new MakeDirectory(); }
  "mkdir"  _directoryname=_DirectoryName() { it.set_directoryname(_directoryname); }
  common_Simple(it)
  { return it; }
}

ChangeDirectoryUp _ChangeDirectoryUp() : {
  ChangeDirectoryUp it = null;
} {
  { it=new ChangeDirectoryUp(); }
  "cd .."  common_Simple(it)
  { return it; }
}

ChangeDirectoryDown _ChangeDirectoryDown() : {
  ChangeDirectoryDown it = null;
  DirectoryName _directoryname;
} {
  { it=new ChangeDirectoryDown(); }
  "cd"  _directoryname=_DirectoryName() { it.set_directoryname(_directoryname); }
  common_Simple(it)
  { return it; }
}

RecursiveCopy _RecursiveCopy() : {
  RecursiveCopy it = null;
  FileName _source;
  FileName _target;
} {
  { it=new RecursiveCopy(); }
  "cp -r"  _source=_FileName() { it.set_source(_source); }
  _target=_FileName() { it.set_target(_target); }
  common_Simple(it)
  { return it; }
}

DiskUsage _DiskUsage() : {
  DiskUsage it = null;
} {
  { it=new DiskUsage(); }
  "du ."  common_Simple(it)
  { return it; }
}

SymbolicLink _SymbolicLink() : {
  SymbolicLink it = null;
  FileName _from;
  FileName _to;
} {
  { it=new SymbolicLink(); }
  "ln -s"  _from=_FileName() { it.set_from(_from); }
  _to=_FileName() { it.set_to(_to); }
  common_Simple(it)
  { return it; }
}

RemoveDirectory _RemoveDirectory() : {
  RemoveDirectory it = null;
  DirectoryName _directoryname;
} {
  { it=new RemoveDirectory(); }
  "rmdir"  _directoryname=_DirectoryName() { it.set_directoryname(_directoryname); }
  common_Simple(it)
  { return it; }
}

CreateEmptyFile _CreateEmptyFile() : {
  CreateEmptyFile it = null;
  FileName _filename;
} {
  { it=new CreateEmptyFile(); }
  "touch"  _filename=_FileName() { it.set_filename(_filename); }
  common_Simple(it)
  { return it; }
}

RemoveFile _RemoveFile() : {
  RemoveFile it = null;
  FileName _filename;
} {
  { it=new RemoveFile(); }
  "rm"  _filename=_FileName() { it.set_filename(_filename); }
  common_Simple(it)
  { return it; }
}

Find _Find() : {
  Find it = null;
  DirectoryName _directoryname;
} {
  { it=new Find(); }
  "find . -name"  _directoryname=_DirectoryName() { it.set_directoryname(_directoryname); }
  "-print"  common_Simple(it)
  { return it; }
}

Echo _Echo() : {
  Echo it = null;
  Message _message;
} {
  { it=new Echo(); }
  "echo"  _message=_Message() { it.set_message(_message); }
  common_Simple(it)
  { return it; }
}

FileName _FileName() : {
  FileName it = null;
  Ident _ident;
} {
  { it=new FileName(); }
  _ident=_Ident() { it.set_ident(_ident); }
  { return it; }
}

DirectoryName _DirectoryName() : {
  DirectoryName it = null;
  Ident _ident;
} {
  { it=new DirectoryName(); }
  _ident=_Ident() { it.set_ident(_ident); }
  { return it; }
}

Message _Message() : {
  Message it = null;
  String _string;
} {
  { it=new Message(); }
  _string=_String() { it.set_string(_string); }
  { return it; }
}

Main _Main() : {
  Main it = null;
} {
  { it=new Main(); }
  { return it; }
}

CommandVisitor _CommandVisitor() : {
  CommandVisitor it = null;
} {
  { it=new CommandVisitor(); }
  { return it; }
}

FileNameVisitor _FileNameVisitor() : {
  FileNameVisitor it = null;
} {
  { it=new FileNameVisitor(); }
  { return it; }
}

File_PList _File_PList() : {
  File_PList it = null;
  Nonempty_File_PList _first;
} {
  { it=new File_PList(); }
  "("  [  _first=_Nonempty_File_PList() { it.set_first(_first); }  ]
  ")"  { return it; }
}

Command_List _Command_List() : {
  Command_List it = null;
  Nonempty_Command_List _first;
} {
  { it=new Command_List(); }
  [  _first=_Nonempty_Command_List() { it.set_first(_first); }  ]
  { return it; }
}

Nonempty_File_PList _Nonempty_File_PList() : {
  Nonempty_File_PList it = null;
  File _it;
  Nonempty_File_PList _next;
} {
  { it=new Nonempty_File_PList(); }
  _it=_File() { it.set_it(_it); }
  [  _next=_Nonempty_File_PList() { it.set_next(_next); }  ]
  { return it; }
}

Nonempty_Command_List _Nonempty_Command_List() : {
  Nonempty_Command_List it = null;
  Command _it;
  Nonempty_Command_List _next;
} {
  { it=new Nonempty_Command_List(); }
  _it=_Command() { it.set_it(_it); }
  [  _next=_Nonempty_Command_List() { it.set_next(_next); }  ]
  { return it; }
}


boolean _boolean() : { Token t; }{
  ( t=<TRUE> { return true; }
  | t=<FALSE> { return false; }
  )
}

char _char() : { Token t; } {
    t=<CHARACTER_LITERAL> { 
       String s = t.image; 
       return unescapifyChar(s.substring(1, s.length()-1)); 
    } 
} 

byte _byte() : { int i; } 
{ i=_int() { return (byte) i; } } 

short _short() : { int i; } 
{ i=_int() { return (short) i; } } 

int _int() : { Number num; } 
{ num=_Number() { return num.intValue(); } } 

long _long() : { Number num; } 
{ num=_Number() { return num.longValue(); } } 

float _float() : { Number num; } 
{ num=_Number() { return num.floatValue(); } } 

double _double() : { Number num; } 
{ num=_Number() { return num.doubleValue(); } } 

Boolean _Boolean() : { Token t; }{
  ( t=<TRUE> { return Boolean.TRUE; }
  | t=<FALSE> { return Boolean.FALSE; }
  )
}

Character _Character() : { char c; } 
{ c=_char() { return new Character(c); } }

Integer _Integer() : { int i; } 
{ i = _int() { return new Integer(i); } }

Long _Long() : { long l; } 
{ l=_long() { return new Long(l); } } 

Float _Float() : { float f; } 
{ f=_float() { return new Float(f); } } 

Double _Double() : { double d; } 
{ d=_double() { return new Double(d); } } 

Number _Number() : 
{
    Token t; 
    String s = null; 
    int radix = 0; 
    Number num = null; 
} {
  ( 
    ( t=<DECIMAL_LITERAL> { 
       s = t.image; 
       radix = 10; 
      } 
    | t=<HEX_LITERAL> { 
       // Strip off the "0x". 
       s = t.image.substring(2, t.image.length()); 
       radix = 16; 
      } 
    | t=<OCTAL_LITERAL> { 
       s = t.image; 
       radix = 8; 
      } 
    ) { 
       switch (s.charAt(s.length()-1)) { 
       case 'l': case 'L': 
         s = s.substring(0, s.length()-1);
         num = new Long(new java.math.BigInteger(s, radix).longValue());
         break; 
       default: 
         num = new Integer(new java.math.BigInteger(s, radix).intValue());
         break; 
       } 
    } 
  | t=<FLOATING_POINT_LITERAL> { 
       s = t.image; 
       switch (s.charAt(s.length()-1)) { 
       case 'd': case 'D': 
           num = Double.valueOf(s.substring(0, s.length()-1)); 
           break; 
       case 'f': case 'F': 
           num = Float.valueOf(s.substring(0, s.length()-1)); 
           break; 
       default: 
           num = Float.valueOf(s); 
           break; 
       } 
    } 
  ) { return num; } 
} 

String _String() : { Token t; } {
    t=<STRING_LITERAL> { 
       String s = t.image; 
       return unescapify(s.substring(1, s.length()-1)); 
    } 
} 

StringBuffer _StringBuffer() : { String s; } 
{ s=_String() { return new StringBuffer(s); } }

Ident _Ident() : { Token t; } {
    t=<IDENTIFIER> { 
       return new Ident(t.image); 
    } 
} 

Text _Text() : { Token t; } {
    t=<TEXT_LITERAL> { 
       String s = t.image; 
       return new Text(s.substring(2, s.length()-2)); 
    } 
} 

Line _Line() : { Token t; } {
    { token_source.SwitchTo(1); } 
    t=<LINE> { 
       return new Line(t.image); 
    } 
} 

Word _Word() : { Token t; } {
    { token_source.SwitchTo(2); } 
    t=<WORD> { 
       return new Word(t.image); 
    } 
} 

// Lexical specification (largely taken from Java.jack): 

SKIP : {
  " " 
| "\t" 
| "\n" 
| "\r" 
| <"//" (~["\n","\r"])* ("\n"|"\r\n")> 
| <"/*" (~["*"])* "*" (~["/"] (~["*"])* "*")* "/"> 
} 
 
TOKEN : { /* LITERALS */
  < DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* (["l","L"])? > 
| 
  < HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ (["l","L"])? > 
| 
  < OCTAL_LITERAL: "0" (["0"-"7"])* (["l","L"])? > 
| 
  < FLOATING_POINT_LITERAL: 
        (["0"-"9"])+ "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])? 
      | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])? 
      | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])? 
      | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"] 
  > 
| 
  < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ > 
| 
  < CHARACTER_LITERAL: 
      "'" 
      (   (~["\'","\\","\n","\r"]) 
        | ("\\" 
            ( ["n","t","b","r","f","\\","\'","\""] 
            | ["0"-"7"] ( ["0"-"7"] )? 
            | ["0"-"3"] ["0"-"7"] ["0"-"7"] 
            ) 
          ) 
      ) 
      "'" 
  >   
| 
  < STRING_LITERAL: 
      "\"" 
      (   (~["\"","\\","\n","\r"]) 
        | ("\\" 
            ( ["n","t","b","r","f","\\","\'","\""] 
            | ["0"-"7"] ( ["0"-"7"] )? 
            | ["0"-"3"] ["0"-"7"] ["0"-"7"] 
            ) 
          ) 
      )* 
      "\"" 
  > 
| 
  < TEXT_LITERAL: 
     ( "(@" 
           (~["@"])* 
           ( "@" ~[")"] 
             (~["@"])* 
           )* 
      "@)" ) 
    | ( "{{" 
           (~["}"])* 
           ( "}" ~["}"] 
             (~["}"])* 
           )* 
      "}}" ) 
  > 
| 
  < TRUE: "true" >
| 
  < FALSE: "false" >
} 

TOKEN : { /* IDENTIFIERS */ 
  < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
|
  < #LETTER:
      [
       "\u0024",
       "\u0041"-"\u005a",
       "\u005f",
       "\u0061"-"\u007a",
       "\u00c0"-"\u00d6",
       "\u00d8"-"\u00f6",
       "\u00f8"-"\u00ff",
       "\u0100"-"\u1fff",
       "\u3040"-"\u318f",
       "\u3300"-"\u337f",
       "\u3400"-"\u3d2d",
       "\u4e00"-"\u9fff",
       "\uf900"-"\ufaff"
      ]
  >
|
  < #DIGIT:
      [
       "\u0030"-"\u0039",
       "\u0660"-"\u0669",
       "\u06f0"-"\u06f9",
       "\u0966"-"\u096f",
       "\u09e6"-"\u09ef",
       "\u0a66"-"\u0a6f",
       "\u0ae6"-"\u0aef",
       "\u0b66"-"\u0b6f",
       "\u0be7"-"\u0bef",
       "\u0c66"-"\u0c6f",
       "\u0ce6"-"\u0cef",
       "\u0d66"-"\u0d6f",
       "\u0e50"-"\u0e59",
       "\u0ed0"-"\u0ed9",
       "\u1040"-"\u1049"
      ]
  >
}

<Line> TOKEN : {
  < LINE: (~["\n","\r"])* > : DEFAULT
}

<Word> SKIP :  { " " | "\t" | "\n" | "\r" }
<Word> TOKEN : {
  < WORD: (~[" ","\t","\n","\r"])* > : DEFAULT
}