CODEGEN.SLC is a simple parser that accepts an expression from input and writes 80x86 compatible assembly code to output. It is written in the SLC language. It is not 100% completed: you can see the beginnings of a peephole optimizer which has not yet been coded.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*                                                                        *
* CODEGEN.SLC     Rowan Crowe <rowan#sensation'net'au>                   *
*                                                                        *
* Simple calculator demonstration, supports addition, subtraction,       *
* multiplication, division, and bracketing.                              *
*                                                                        *
* This is similar to CALC.MOO supplied in COMPIxxx.ZIP downloadable via  *
* http://www.rowan.sensation.net.au/slc.html , except that it doesn't    *
* parse the line into an array prior to evaluating it.                   *
*                                                                        *
* The code could still be a lot neater by not relying on using global    *
* variables across several functions.                                    *
*                                                                        *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

extern int itostr()
extern int strtoui()
extern int input()
extern int puts()
extern int putc()
extern int isdigit()
extern int isalpha()
extern int tinymeminit()
extern int malloc()
extern int free()
extern void abort()

define REG_AX       0
define REG_BX       1

define OP_PUSHREG   0
define OP_POPREG    1
define OP_ADDREG    2
define OP_SUBREG    3
define OP_DIVREG    4
define OP_MULREG    5

global int errno
global char *p
global int errorflag
global int locallabel

int evaluate () {
  compare()
}

int compare () {
  int t
  add_subtract()
  while ((*p != 0) && ((*p == '=' && *(p+1) == '=') || (*p == '<') || (*p == '>'))) {
    if (*p == '<') {
      p = p + 1
      puts("\tpush\tax\n")
      add_subtract()
      puts("\tpop\tbx\n\tcmp\tax,bx\n\tmov\tax,-1\n")
      t = locallabel
      locallabel = locallabel + 1
      puts("\tjl\tLL")
      puts(itostr("1234567", locallabel))
      puts("\n\tinc\tax\nLL")
      puts(itostr("1234567", locallabel))
      puts(":\n")
    }
    if (*p == '>') {
      p = p + 1
      puts("\tpush\tax\n")
      add_subtract()
      puts("\tpop\tbx\n\tcmp\tax,bx\n\tmov\tax,-1\n")
      t = locallabel
      locallabel = locallabel + 1
      puts("\tjg\tLL")
      puts(itostr("1234567", locallabel))
      puts("\n\tinc\tax\nLL")
      puts(itostr("1234567", locallabel))
      puts(":\n")
    }
  }
}

int add_subtract() {
  divide_multiply()
  while ((*p != 0) && ((*p == '+') || (*p == '-'))) {
    if (*p == '+') {
      p = p + 1
      puts("\tpush\tax\n")
      divide_multiply()
      puts("\tpop\tbx\n\tadd\tax,bx\n")
    }
    if (*p == '-') {
      p = p + 1
      puts("\tpush\tax\n")
      divide_multiply()
      puts("\tmov\tbx,ax\n\tpop\tax\n\tsub\tax,bx\n")
    }
  }
}

int divide_multiply() {
  bracket()
  while ( (*p != 0) && ( (*p == '/') || (*p == '*') ) ) {
    if (*p == '/') {
      p = p + 1
      puts("\tpush\tax\n")
      bracket()
      puts("\tmov\tbx,ax\n\tpop\tax\n\tdiv\tbx\n")
    }
    if (*p == '*') {
      p = p + 1
      puts("\tpush\tax\n")
      bracket()
      puts("\tmov\tbx,ax\n\tpop\tax\n\tmul\tbx\n")
    }
  }
}

int bracket() {
  int rv

  remove_whitespace()

  if (isdigit(*p) || isalpha(*p)) {
    fetchname()
    return
  }
  switch(*p) {
    case '(' {
      p = p + 1
      rv = add_subtract()
      if (*p != ')') {
        puts("syntax error: expected ')' closing bracket\n")
        errorflag = 1
        return 0
      } else {
        p = p + 1
        remove_whitespace()
        return rv
      }
    }
    case '-' {
      p = p + 1
      if (isdigit(*p)) {
        puts("-")
        puts(fetchname())
      }
    }
    case else {
      puts("syntax error: unexpected token '")
      putc(*p)
      puts("'\n")
      *p = '0'
      errorflag = 1
      return 0
    }
  }
}

int fetchname() {
  puts("\tmov\tax,")
  while ((isdigit(*p) || isalpha(*p)) && *p != 0) {
    putc(*p)
    p = p + 1
  }
  puts("\n")
  remove_whitespace()
}
int fetchnumber() {
  char *tmpbuf
  char *d

  if ((tmpbuf = malloc(20)) == -1) {
    puts("memory allocation failed.\n")
    abort(0)
  }

  d = tmpbuf
  while (isdigit(*p) && *p != 0) {
    *d = *p
    p = p + 1
    d = d + 1
  }
  *d = 0
  remove_whitespace()
  free(tmpbuf)
  puts(strtoui(tmpbuf))
}

void remove_whitespace() {
  while (*p == ' ') {
    p = p + 1
  }
}

void add_peep(int opcode, int parm1, int parm2) {
}

int main() {
  int rv
  char *origp
  int exitnow

  if ((rv = tinymeminit(4096)) == -1) {
    puts("memory init failed.\n")
    abort(0)
  }
  if ((p = malloc(51)) == -1) {
    puts("memory allocation failed.\n")
    abort(0)
  }
  origp = p

  exitnow = 0
  locallabel = 0
  while (exitnow == 0) {
    p = origp
    errorflag = 0
    puts("> ")
    rv = input(p, 50)
    puts("\n; ")
    puts(p)
    puts("\n")
    if (*p != 0) {
      rv = evaluate()
      if (errorflag == 0) {
        puts("\n")
      }
    } else {
      exitnow = 1
    }
  }
  puts("\nBye!\n")
  free(p)  /* ignore return value */
  return 0
}




Return to SLC homepage