#include "Compiler.h" #include "Instruction.h" #include "Nil.h" #include "Void.h" #include "Boolean.h" #include "Cons.h" #include "defs.h" Symbol *lambdaSym; Symbol *quoteSym; Symbol *defineSym; Symbol *ifSym; Symbol *letrecSym; Symbol *beginSym; @implementation Compiler + (void) initialize { lambdaSym = [Symbol forString: "lambda"]; [lambdaSym retain]; quoteSym = [Symbol forString: "quote"]; [quoteSym retain]; defineSym = [Symbol forString: "define"]; [defineSym retain]; ifSym = [Symbol forString: "if"]; [ifSym retain]; letrecSym = symbol("letrec"); [letrecSym retain]; beginSym = symbol("begin"); [beginSym retain]; } + (id) newWithLambda: (SchemeObject*) xp scope: (Scope*) sc { return [[self alloc] initWithLambda: xp scope: sc]; } - (id) initWithLambda: (SchemeObject*) xp scope: (Scope*) sc { self = [super init]; sexpr = xp; scope = sc; code = [CompiledCode new]; err = nil; return self; } - (void) emitBuildEnvironment: (SchemeObject *) arguments { local integer count, index; local SchemeObject *cur; scope = [Scope newWithOuter: scope]; count = 0; for (cur = arguments; [cur isKindOfClass: [Cons class]]; cur = [(Cons*) cur cdr]) { count++; } [code minimumArguments: count]; if (cur != [Nil nil]) { count++; } [code addInstruction: [Instruction opcode: MAKEENV operand: count]]; [code addInstruction: [Instruction opcode: LOADENV]]; cur = arguments; for (index = 0; index < count; cur = [(Cons*) cur cdr]) { if ([cur isKindOfClass: [Cons class]]) { [scope addName: (Symbol*) [(Cons*) cur car]]; [code addInstruction: [Instruction opcode: SET operand: index]]; } else if ([cur isKindOfClass: [Symbol class]]) { [scope addName: (Symbol*) cur]; [code addInstruction: [Instruction opcode: SETREST operand: index]]; break; } else { err = [Error type: "syntax" message: "Invalid entry in argument list" by: arguments]; return; } index++; } } - (void) emitSequence: (SchemeObject*) expressions flags: (integer) fl { local SchemeObject *cur; for (cur = expressions; cur != [Nil nil]; cur = [(Cons*) cur cdr]) { if ([(Cons*) cur cdr] == [Nil nil] && (fl & TAIL)) { [self emitExpression: [(Cons*) cur car] flags: fl]; } else { [self emitExpression: [(Cons*) cur car] flags: fl & ~TAIL]; } if (err) return; } } - (void) emitVariable: (Symbol*) sym { local integer depth = [scope depthOf: sym]; local integer index = [scope indexOf: sym]; [code addInstruction: [Instruction opcode: LOADENV]]; if (depth != -1) { for (; depth; depth--) { [code addInstruction: [Instruction opcode: GETLINK]]; } [code addInstruction: [Instruction opcode: GET operand: index]]; } else { index = [code addConstant: sym]; [code addInstruction: [Instruction opcode: LOADLITS]]; [code addInstruction: [Instruction opcode: GET operand: index]]; [code addInstruction: [Instruction opcode: GETGLOBAL]]; } } - (void) emitDefine: (SchemeObject*) expression { local integer index = 0; if (![expression isKindOfClass: [Cons class]] || ![[(Cons*) expression cdr] isKindOfClass: [Cons class]]) { err = [Error type: "syntax" message: "Malformed define statement" by: expression]; return; } if ([[(Cons*) expression car] isKindOfClass: [Cons class]]) { index = [code addConstant: [(Cons*) [(Cons*) expression car] car]]; [self emitLambda: cons(lambdaSym, cons([(Cons*) [(Cons*) expression car] cdr], [(Cons*) expression cdr]))]; if (err) return; } else if ([[(Cons*) expression car] isKindOfClass: [Symbol class]]) { index = [code addConstant: [(Cons*) expression car]]; [self emitExpression: [(Cons*) [(Cons*) expression cdr] car] flags: 0]; if (err) return; } else { err = [Error type: "syntax" message: "Malformed define statement" by: expression]; return; } [code addInstruction: [Instruction opcode: PUSH]]; [code addInstruction: [Instruction opcode: LOADLITS]]; [code addInstruction: [Instruction opcode: GET operand: index]]; [code addInstruction: [Instruction opcode: SETGLOBAL]]; } - (void) emitIf: (SchemeObject*) expression flags: (integer) fl { local Instruction *falseLabel, *endLabel; local integer index; if (![expression isKindOfClass: [Cons class]] || ![[(Cons*) expression cdr] isKindOfClass: [Cons class]]) { err = [Error type: "syntax" message: "Malformed if expression" by: expression]; } falseLabel = [Instruction opcode: LABEL]; endLabel = [Instruction opcode: LABEL]; [self emitExpression: [(Cons*) expression car] flags: fl & ~TAIL]; if (err) return; [code addInstruction: [Instruction opcode: IFFALSE label: falseLabel]]; [self emitExpression: [(Cons*) [(Cons*) expression cdr] car] flags: fl]; if (err) return; [code addInstruction: [Instruction opcode: GOTO label: endLabel]]; [code addInstruction: falseLabel]; if ([(Cons*) [(Cons*) expression cdr] cdr] == [Nil nil]) { index = [code addConstant: [Void voidConstant]]; [code addInstruction: [Instruction opcode: LOADLITS]]; [code addInstruction: [Instruction opcode: GET operand: index]]; } else { [self emitExpression: [(Cons*) [(Cons*) [(Cons*) expression cdr] cdr] car] flags: fl]; if (err) return; } [code addInstruction: endLabel]; } - (void) emitLetrec: (SchemeObject*) expression flags: (integer) fl { local SchemeObject *bindings; local integer count; if (!isList(expression) || !isList([(Cons*) expression car]) || ![[(Cons*) expression cdr] isKindOfClass: [Cons class]]) { err = [Error type: "syntax" message: "Malformed letrec expression" by: expression]; } scope = [Scope newWithOuter: scope]; count = 0; for (bindings = [(Cons*) expression car]; bindings != [Nil nil]; bindings = [(Cons*) bindings cdr]) { [scope addName: (Symbol*) [(Cons*) [(Cons*) bindings car] car]]; count++; } [code addInstruction: [Instruction opcode: MAKEENV operand: count]]; count = 0; for (bindings = [(Cons*) expression car]; bindings != [Nil nil]; bindings = [(Cons*) bindings cdr]) { [self emitSequence: [(Cons*) [(Cons*) bindings car] cdr] flags: fl & ~TAIL]; [code addInstruction: [Instruction opcode: PUSH]]; [code addInstruction: [Instruction opcode: LOADENV]]; [code addInstruction: [Instruction opcode: SET operand: count]]; count++; } [self emitSequence: [(Cons*) expression cdr] flags: fl]; [code addInstruction: [Instruction opcode: POPENV]]; scope = [scope outer]; } - (void) emitExpression: (SchemeObject*) expression flags: (integer) fl { if ([expression isKindOfClass: [Cons class]]) { [code source: [expression source]]; [code line: [expression line]]; if ([(Cons*) expression car] == lambdaSym) { [self emitLambda: expression]; } else if ([(Cons*) expression car] == quoteSym) { [self emitConstant: [(Cons*) [(Cons*) expression cdr] car]]; } else if ([(Cons*) expression car] == defineSym) { [self emitDefine: [(Cons*) expression cdr]]; } else if ([(Cons*) expression car] == ifSym) { [self emitIf: [(Cons*) expression cdr] flags: fl]; } else if ([(Cons*) expression car] == letrecSym) { [self emitLetrec: [(Cons*) expression cdr] flags: fl]; } else if ([(Cons*) expression car] == beginSym) { [self emitSequence: [(Cons*) expression cdr] flags: fl]; } else { [self emitApply: expression flags: fl]; } } else if ([expression isKindOfClass: [Symbol class]]) { [self emitVariable: (Symbol*) expression]; } else { [self emitConstant: expression]; } } - (void) emitArguments: (SchemeObject*) expression { if (expression == [Nil nil]) { return; } else { [self emitArguments: [(Cons*) expression cdr]]; if (err) return; [self emitExpression: [(Cons*) expression car] flags: 0]; if (err) return; [code addInstruction: [Instruction opcode: PUSH]]; } } - (void) emitApply: (SchemeObject*) expression flags: (integer) fl { local Instruction *label = [Instruction opcode: LABEL]; if (!(fl & TAIL)) { [code addInstruction: [Instruction opcode: MAKECONT label: label]]; } [self emitArguments: [(Cons*) expression cdr]]; if (err) return; [self emitExpression: [(Cons*) expression car] flags: fl & ~TAIL]; if (err) return; [code addInstruction: [Instruction opcode: CALL]]; [code addInstruction: label]; } - (void) emitLambda: (SchemeObject*) expression { local Compiler *compiler = [Compiler newWithLambda: expression scope: scope]; local SchemeObject *res; local integer index; res = [compiler compile]; if ([res isError]) { err = (Error *) res; return; } index = [code addConstant: res]; [code addInstruction: [Instruction opcode: LOADLITS]]; [code addInstruction: [Instruction opcode: GET operand: index]]; [code addInstruction: [Instruction opcode: MAKECLOSURE]]; } - (void) emitConstant: (SchemeObject*) expression { local integer index; index = [code addConstant: expression]; [code addInstruction: [Instruction opcode: LOADLITS]]; [code addInstruction: [Instruction opcode: GET operand: index]]; } - (void) checkLambdaSyntax: (SchemeObject*) expression { if (![expression isKindOfClass: [Cons class]] || [(Cons*) expression car] != lambdaSym || [(Cons*) expression cdr] == [Nil nil] || [(Cons*) [(Cons*) expression cdr] cdr] == [Nil nil]) { err = [Error type: "syntax" message: "malformed lambda expression" by: expression]; } } - (SchemeObject*) compile { [self checkLambdaSyntax: sexpr]; if (err) { return err; } [self emitBuildEnvironment: [(Cons*) [(Cons*) sexpr cdr] car]]; if (err) { return err; } [self emitSequence: [(Cons*) [(Cons*) sexpr cdr] cdr] flags: TAIL]; if (err) { return err; } [code addInstruction: [Instruction opcode: RETURN]]; [code compile]; return code; } - (void) markReachable { [code mark]; [sexpr mark]; [scope mark]; } @end