/*
 * CLAW compiler.  © Copyright 2003 Terrasoft Technologies.  This program
 * is governed by the GNU public license.  See the file COPYING.TXT for details.
 *
 * This compiler generates native machine code for whatever processor.
 * It is currently configured to generate an MS-DOS .COM file, but it
 * should be relatively easy to alter.
 */

#include <stdio.h>

void compile();              // prototyping, don't leave home without it

unsigned short location = 3; // oh, those silly unsigned's... ha ha.
unsigned short datasize = 1;
unsigned short ptr = 1;
FILE *z, *Z;                 // FILES: z = the file being compiled, Z = compiled output
char b;
int q;
unsigned short n;

main( int argc, char *argv[] ) {
  q=argc;                                      // doo doo doo, making global variables, doo doo doo!
  
  if(q<3)                                      // if there are less than three arguments
    printf("usage: clawc [input] [output]\n"); // tell them how to fucking use clawC
  else {                                       // otherwise
  if ( z = fopen( argv[1], "r" ) )             // if you can open the file for input
  {                                            // then
    if ( Z = fopen( argv[2], "wb" ) )          // if you can open the file for output
    {                                          // THEN
      fwrite( "\xbe\x00\x00", 1, 3, Z );       // start doing that crazy COM shit
      compile();
      fwrite( "\xb8\x00\x4c\xcd\x21", 1, 5, Z );
      location += 261;
      for ( ptr = 0; ptr < datasize; ptr++ )
      {
        fwrite( "\x00", 1, 1, Z );
      }
      fseek( Z, 1, SEEK_SET );
      fwrite( &location, 1, 2, Z );
      fclose( Z );
    }
    else                                                            // else, if you CAN'T write to the file
        printf("error: file `%s' can not be written to\n",argv[2]); // then bitch
    fclose(z);                                                      // close the fucking file
      }
    else                                                            // else, if you can't read the file
        printf("error: file `%s' does not exist\n",argv[1]);        // then bitch
    }
}

void compile() {
  unsigned short m;
  while( ( b=getc(z) ) != EOF )        // while the end of the file hasn't been reached
  {
    switch ( b )
    {
    // do all of this shit
      case '<': fwrite( "\x4e", 1, 1, Z ); location++; ptr--; break;
      case '>':
        fwrite( "\x46", 1, 1, Z );
        location++;
        ptr++;
        if ( ptr > datasize ) datasize = ptr;
        break;
      case '+': fwrite( "\xfe\x04", 1, 2, Z ); location += 2; break;
      case '-': fwrite( "\xfe\x0c", 1, 2, Z ); location += 2; break;
      case '.':
        fwrite( "\xb4\x40\xbb\x01\x00\x89\xd9\x89\xf2\xcd\x21", 1, 11, Z );
        location += 11;
        break;
      case ',':
        fwrite( "\xb4\x01\xcd\x21\x3c\x0d\x75\x07\xb8\x0a\x02\xb2\x0a\xcd\x21\x88\x04", 1, 17, Z );
        location += 17;
        break;
      case '[':
        m = location;
        fwrite( "\x80\x3c\x00\x75\x03\xe9\x00\x00", 1, 8, Z );
        location += 8;
        compile();
        fwrite( "\xe9", 1, 1, Z );
        location += 3;
        n = m - location;
        fwrite( &n, 1, 2, Z );
        fseek( Z, m + 6, SEEK_SET );
        n = location - m - 8;
        fwrite( &n, 1, 2, Z );
        fseek( Z, 0, SEEK_END );
        break;
      case ']': return;
    }
  }
}