NietShell

<earlier> ^| upward |^ <later>


No sml on jvm

I started working on Simpletron again about a month ago. It is one of my open loops, given that I didn't finish the project to completion. Simpletron is a shorthand for a set of exercises in the Deitel How to Program books of various languages. Specifically, they involve making a simple vm and a compiler for a subset of Basic. Each also has advanced problems that I didn't undertake: loops, functions, arrays, and strings. I made both in python - to learn how to use it - and backed off from the advanced versions.

void execute( instructionVal ){
    signal = cpu.result( instructionVal );
    moveData( signal.path, signal.cargo );
}

The non-magpie reason stemmed from the fact that I organized the code poorly for extending its functionality. The computer was fine, but the compiler took a line, split off its number, and then sent it to a function that both parsed and emitted the final code (to a holding bank for a second pass). That works okay for the small language presented, no statement is composed of other statements. But, adding stack dependent instructions was a chore. So, a month ago, I started to pull the parsing aspects of each instruction apart from the code generation.

void result( storedInstrAlready ) {
switch( storedInstrAlready )
 case Instr.INPUT:
    return new Signal( pair.I_C, instrVal );
 case Instr.STORE:
    return new Signal( pair.C_R, instrVal );
 [etc]
}

But, refactoring began to lose mindshare against a new version. I'm supposed to be practicing Java anyway, so why not start over? Okay, just the simpletron, to permit testing the simple_compiler's output on another implementation? Because I already knew where this was going, I could design it in a good object oriented style with message passing, and so on.

void moveData( path, cargo ) {
switch( path )
{
 case pair.I_C: {
    brain.receive( stdin.emit( cargo ) );
    break; }
 case pair.S_C: {
    brain.receive( stdout.emit( cargo ) );
    break; }
 case pair.C_C: {
    brain.receive( brain.emit( cargo ) );
    break; }    // it handles distinguishing branch & math
}

Eventually it would be nice to make a gui, one of the benefits of using java, and I fussed over how to evolve this simulation into an mvc architecture. The MOVE paradigm popped up instead. MOVE involves separating the program state into a Model, the actions into an Operation graph, the gui into a View heirarchy, and updates between these via Event logic.

emit( info ) {
 switch( info.instr ){
 case Inst.BRANCH:
    return new Ping( info.instr, operand );
 case Inst.BR_NEG:
    if ( acc <= 0 ){
        return new Ping( info.instr, operand ) }
    else {
        return new Ping( info.instr, pc ) }
 case Inst.ADD:
    int temp = acc + operand;
    if validSize( temp )
        return new Ping( info.instr, temp );
    else
        throw sizeException;
}

In this regard, the values in the cpu's registers & ram hole up in the model. The cpu's instructions are embodied in Operations objects that modify that data in response to Events coming from the View. The gui updates when the model fires a (value) changed event. Suffice that this is not how I was building the simpletron, even slightly. I tabled the gui idea. Better to pursue that after I've made a working version. (It wouldn't be scrapped, so much as archived as a backup implementation.)

receive( Ping instr_result ){
 switch( instr_result.opC ){
  case Inst.BRA:
    pc = instr_result.answ;
  case Inst.ADD:
    acc = instr_result.answ;
}

Here I started to wonder if this branch was a navel-gazing exercise. I'd already implemented a working version of Simpletron. Surely, growth comes from making new things, rather than reexpressing solved problems. In time, I started looking at MMIX again. MMIX is Donald Knuth's example computer for this Art of Computer Programming encyclopedia. I woke up when I noticed (again) that it has 256 registers and, oh yeah, it pipelines instructions, and, and, and.

This project isn't about simulating a cpu, though it involves a minimalistic one. This project isn't about making a compiler, though it involves one. My concern for this project is to bring it to its ultimate conclusion. There are four pieces missing from the simple compiler and laying this demon to rest means putting them in.

SIGNALS
Read : inp -> cpu
Writ : cpu -> out
Load : ram -> cpu
Stor : cpu -> ram
+-/* : cpu -> cpu
Bran : cpu -> cpu
Halt : cpu -> sml

Earlier, I couched it in the guise of practicing refactoring. This is about the most amenable codebase I am likely to confront in that regard. Not because it is easy to refactor (sigh), but because none of the naming/indentation/etc conventions will differ from mine (except where I've matured, go figure).

So, I had to surrender this branch. I promised myself that I won't touch the java branch for the forseeable future. I have legitimate projects to pursue that let me practice building things in java. For example, now that I have two monitors, I can't see the time in the bottom monitor easily. I turned on the ugh, analog clock widget, but I can't switch to it. So, to see it, I have to swap to the desktop or not run programs full-screened.

I've punched farther off the track. I am glad I was reigned back in before too long. Plus, when I write the next compiler I'd rather make it for a lisp and work with a more complex backend, maybe the LLVM.

© Nicholas Prado <earlier> ^| upward |^ <later> category: reflection tags: java - simpletron -