MinIPS*1のアセンブラっぽいなにか

D言語(しかもDMD2.007以降でしかコンパイルできない。それ以降でもコンパイルできるか保証は無い)で書いたMinIPS(電通大情報工学科にて使われてる教育用プロセッサ)のアセンブラとか、範囲限定され過ぎだろと思った。なのでlex/yacc使って書き直してみました。

とりあえずWindowsバイナリこの辺 http://konbu.s13.xrea.com/lib/minika.exe

なんかまあ標準入力で受けて標準出力に吐きます。出力は相変わらず16進数表現のマシン語列です。

% make
yacc -d -y minika.y
lex -I minika.l
mv y.tab.c minika.c
cc lex.yy.c minika.c optable.h -ll -o minika
% cat hoge.s
add $1, $2, $3
sub $1, $2, $3
nop
bne $1, $0, 10h
beq $1, $0, -2
% ./minika <hoge.s
00430820
00430822
00000000
14010010
1001FFFE

ねむい。以下コード。

TARGET = minika
SOURCES = minika.l minika.y optable.h

all: minika

minika: lex.yy.c minika.c optable.h
        $(CC) $^ -ll -o $@

lex.yy.c: minika.l y.tab.h
        $(LEX) -I $<
y.tab.h: minika.y
        $(YACC) -d -y $<
y.tab.c: minika.y
        $(YACC) -d -y $<
minika.c: y.tab.c
        mv $< $@

最近Makefile書いてなかったんで、微妙に手間取った。

/**
* minika.l
**/
%{
#include "y.tab.h"
int hex2int(char *hval)
{
  int ival = 0, i;
  for(;*hval;++hval){
    if(*hval>='0' && *hval<='9'){
      ival = ival*16 + *hval - '0';
    }
    else if(*hval>='A' && *hval<='F'){
      ival = ival*16 + *hval - 'A' + 10;
    }
    else if(*hval>='a' && *hval<='f'){
      ival = ival*16 + *hval - 'a' + 10;
    }
    else{
      return ival;
    }
  }
  return ival;
}
%}

ALPHA [a-zA-Z]
NUM [0-9]
ALNUM [0-9a-zA-Z]
HEX [0-9a-fA-F]
ID [a-zA-Z_][0-9a-zA-Z_]*
RET [\r\n]|\r\n
SP [ \t]

%state COMMENT
%%

<INITIAL>{ID} {
  yylval.sval = yytext;
  return(IDENT);
}
<INITIAL>[0-9]+ {
  yylval.ival = atoi(yytext);
  return(INTEGER);
}
<INITIAL>{HEX}+h {
  yylval.ival = hex2int(yytext);
  return(INTEGER);
};
<INITIAL>\: return(COL);
<INITIAL>\$ return(DOL);
<INITIAL>\, return(CAMMA);
<INITIAL>\- return(MINUS);
<INITIAL>\; {BEGIN(COMMENT);}
<INITIAL>{RET} return(EOL);
<INITIAL>{SP} ;
<INITIAL>\( return(LPAREN);
<INITIAL>\) return(RPAREN);
<INITIAL>. {
  yyerror("Illegal character"); 
  return(EOL);
}
<COMMENT>{RET} {BEGIN(INITIAL);return(EOL);}
<COMMENT>[^\r\n] ;
%%

たぶんほとんど変わってないな。MINUS追加したくらい。

/**
* asm.y
**/
%{
#include <stdio.h>
#include <string.h>
#include "optable.h"
#define MAXCHAR 1000
char strbuf[MAXCHAR];

#define PROGSIZE 60000
Field program[PROGSIZE];
int counter = 0;
int assoc_search(IntTable *, char *);
int printField(Field *);
Field field_search(FieldTable *, char *);
Field *field_copy(Field *, Field);

%}

%union {
   int ival;
   float fval;
   char *sval;
}

%token <sval> IDENT
%token <ival> INTEGER
%token COL DOL CAMMA MINUS LPAREN RPAREN
%token EOL

%type <ival> integer
%type <sval> ident

%%
input :
      | input line
      ;

line : EOL
     | rform EOL
     | iform EOL
     | jform EOL
     ;
rform : ident DOL integer CAMMA DOL integer CAMMA DOL integer{
        Field *field = &program[counter++];
        field->type = RForm;
        field->op = 0;
        field->rs = $6;
        field->rt = $9;
        field->rd = $3;
        field->shamt = 0;
        field->fun = assoc_search(&funtable, $1);
      }
      | ident DOL integer {
        Field *field = &program[counter++];
        field->type = RForm;
        field->op = 0;
        field->rs = $3;
        field->rt = 0;
        field->rd = 0;
        field->shamt = 0;
        field->fun = assoc_search(&funtable, $1);
      }
      | ident DOL integer CAMMA DOL IDENT {
        Field *field = &program[counter++];
        field->type = RForm;
        field->op = assoc_search(&optable, $1);
        field->rs = 0;
        field->rt = 14;
        field->rd = $3;
        field->shamt = 0;
        field->fun = 0;
      }
      | ident DOL IDENT CAMMA DOL integer {
        Field *field = &program[counter++];
        field->type = RForm;
        field->op = assoc_search(&optable, $1);
        field->rs = 4;
        field->rt = $6;
        field->rd = 12;
        field->shamt = 0;
        field->fun = 0;
      }
      | ident {
        Field *field = &program[counter++];
        field_copy(field, field_search(&constTable, $1));
      }
      ;
iform : ident DOL integer CAMMA DOL integer CAMMA integer{
        Field *field = &program[counter++];
        int fun;
        if((fun = assoc_search(&funtable, $1))!=-1){
          field->type = RForm;
          field->op = 0;
          field->rs = 0;
          field->rt = $6;
          field->rd = $3;
          field->shamt = $8;
          field->fun = fun;
        }
        else{
          field->type = IForm;
          field->op = assoc_search(&optable, $1);
          field->rs = $6;
          field->rt = $3;
          field->imm = $8;
        }
      }
      | ident DOL integer CAMMA integer LPAREN DOL integer RPAREN{
        Field *field = &program[counter++];
        field->type = IForm;
        field->op = assoc_search(&optable, $1);
        field->rs = $8;
        field->rt = $3;
        field->imm = $5;
      }
      | ident DOL integer CAMMA integer{
        Field *field = &program[counter++];
        field->type = IForm;
        field->op = assoc_search(&optable, $1);
        field->rs = 0;
        field->rt = $3;
        field->imm = $5;
      }
      ;
jform : ident integer {
        Field *field = &program[counter++];
        field->type = JForm;
        field->op = assoc_search(&optable, $1);
        field->target = $2;
      }
      ;
ident : IDENT { $$ = strncpy(strbuf, $1, MAXCHAR);}
      ;
integer : INTEGER { $$ = $1;}
        | MINUS INTEGER { $$ = - $2;}
        ;

%%

int assoc_search(IntTable *assoc, char *key)
{
  int val, i;
  for(i=0;i<assoc->len;++i){
    if(strcmp(key, assoc->data[i].key)==0){
      return assoc->data[i].val;
    }
  }
  return -1;
}
void printBin(unsigned int val, int len)
{
  for(;len>0;--len){
    int x = (val&((1<<len-1))) != 0;
    putchar('0'+x);
  }
}
int printFieldBin(Field *field)
{
  switch(field->type){
  default:
  case RForm:
    printBin(field->op, 6);
    printBin(field->rs, 5);
    printBin(field->rt, 5);
    printBin(field->rd, 5);
    printBin(field->shamt, 5);
    printBin(field->fun, 6);
    break;
  case IForm:
    printBin(field->op, 6);
    printBin(field->rs, 5);
    printBin(field->rt, 5);
    printBin(field->imm, 16);
    break;
  case JForm:
    printBin(field->op, 6);
    printBin(field->target, 26);
    break;
  }
  return 1;
}
unsigned long field2ulong(Field *field)
{
  unsigned long result = 0;
  switch(field->type){
  default:
  case RForm:
    result = field->op<<26;
    result |= field->rs<<21;
    result |= field->rt<<16;
    result |= field->rd<<11;
    result |= field->shamt<<6;
    result |= field->fun;
    return result;
  case IForm:
    result = field->op<<26;
    result |= field->rs<<21;
    result |= field->rt<<16;
    result |= (field->imm)&65535;
    return result;
  case JForm:
    result = field->op<<26;
    result |= field->target;
    return result;
  }
}
Field field_search(FieldTable *fassoc, char *key)
{
  int val, i;
  for(i=0;i<fassoc->len;++i){
    if(strcmp(key, fassoc->data[i].key)==0){
      return fassoc->data[i].field;
    }
  }
  return fassoc->data[0].field;
}
Field *field_copy(Field *dest, Field src)
{
  *dest = src;
  return dest;
}
int yyerror(const char *s)
{
  fprintf(stderr, "%s\n", s);
}
int main()
{
  int pc;
  yyparse();
  for(pc=0;pc<counter;++pc){
    printf("%08X", field2ulong(&program[pc]));
    putchar('\n');
  }
}

てきとうだなあ。

test