add logical ops, add numbers
This commit is contained in:
		
							parent
							
								
									bf38431165
								
							
						
					
					
						commit
						9d65790e5d
					
				
							
								
								
									
										47
									
								
								src/'
								
								
								
								
							
							
						
						
									
										47
									
								
								src/'
								
								
								
								
							| 
						 | 
				
			
			@ -1,47 +0,0 @@
 | 
			
		|||
#include "common.h"
 | 
			
		||||
#include "vm.h"
 | 
			
		||||
 | 
			
		||||
VM vm; 
 | 
			
		||||
 | 
			
		||||
void newVM() {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void freeVM() {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static InterpretResult run() {
 | 
			
		||||
#define READ_BYTE() (*vm.ip++)
 | 
			
		||||
#define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()])
 | 
			
		||||
 | 
			
		||||
  for (;;) {
 | 
			
		||||
#ifdef DEBUG_TRACE_EXECUTION
 | 
			
		||||
    disassembleInstruction(vm.chunk,
 | 
			
		||||
                           (int)(vm.ip - vm.chunk->code));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    uint8_t instruction;
 | 
			
		||||
    switch (instruction = READ_BYTE()) {
 | 
			
		||||
      case OP_CONSTANT: {
 | 
			
		||||
        Value constant = READ_CONSTANT();
 | 
			
		||||
        printValue(constant);
 | 
			
		||||
        printf("\n");
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case OP_RETURN: {
 | 
			
		||||
        return INTERPRET_OK;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#undef READ_BYTE
 | 
			
		||||
#undef READ_CONSTANT
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
InterpretResult interpret(Chunk* chunk) {
 | 
			
		||||
  vm.chunk = chunk;
 | 
			
		||||
  vm.ip = vm.chunk->code;
 | 
			
		||||
  return run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8,10 +8,17 @@
 | 
			
		|||
typedef enum {
 | 
			
		||||
  OP_NOOP,
 | 
			
		||||
  OP_CONSTANT,
 | 
			
		||||
  OP_NIL,
 | 
			
		||||
  OP_TRUE,
 | 
			
		||||
  OP_FALSE,
 | 
			
		||||
  OP_EQUAL,
 | 
			
		||||
  OP_GREATER,
 | 
			
		||||
  OP_LESS,
 | 
			
		||||
  OP_ADD,
 | 
			
		||||
  OP_SUBTRACT,
 | 
			
		||||
  OP_MULTIPLY,
 | 
			
		||||
  OP_DIVIDE,
 | 
			
		||||
  OP_NOT,
 | 
			
		||||
  OP_NEGATE,
 | 
			
		||||
  OP_RETURN, 
 | 
			
		||||
} OpCode;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -141,7 +141,7 @@ static void grouping() {
 | 
			
		|||
 | 
			
		||||
static void number() {
 | 
			
		||||
  double value = strtod(parser.previous.start, NULL);
 | 
			
		||||
  emitConstant(value);
 | 
			
		||||
  emitConstant(NUMBER_VAL(value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void binary() {
 | 
			
		||||
| 
						 | 
				
			
			@ -150,6 +150,12 @@ static void binary() {
 | 
			
		|||
  parsePrecedence((Precedence)(rule->precedence + 1));
 | 
			
		||||
 | 
			
		||||
  switch (operatorType) {
 | 
			
		||||
    case TOKEN_BANG_EQUAL:    emitBytes(OP_EQUAL, OP_NOT); break;
 | 
			
		||||
    case TOKEN_EQUAL_EQUAL:   emitByte(OP_EQUAL); break;
 | 
			
		||||
    case TOKEN_GREATER:       emitByte(OP_GREATER); break;
 | 
			
		||||
    case TOKEN_GREATER_EQUAL: emitBytes(OP_LESS, OP_NOT); break;
 | 
			
		||||
    case TOKEN_LESS:          emitByte(OP_LESS); break;
 | 
			
		||||
    case TOKEN_LESS_EQUAL:    emitBytes(OP_GREATER, OP_NOT); break;
 | 
			
		||||
    case TOKEN_PLUS:          emitByte(OP_ADD); break;
 | 
			
		||||
    case TOKEN_MINUS:         emitByte(OP_SUBTRACT); break;
 | 
			
		||||
    case TOKEN_STAR:          emitByte(OP_MULTIPLY); break;
 | 
			
		||||
| 
						 | 
				
			
			@ -158,6 +164,15 @@ static void binary() {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void literal() {
 | 
			
		||||
  switch (parser.previous.type) {
 | 
			
		||||
    case TOKEN_FALSE: emitByte(OP_FALSE); break;
 | 
			
		||||
    case TOKEN_NIL: emitByte(OP_NIL); break;
 | 
			
		||||
    case TOKEN_TRUE: emitByte(OP_TRUE); break;
 | 
			
		||||
    default: return; // Unreachable.
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void unary() {
 | 
			
		||||
  TokenType operatorType = parser.previous.type;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -166,6 +181,7 @@ static void unary() {
 | 
			
		|||
 | 
			
		||||
  // Emit the operator instruction.
 | 
			
		||||
  switch (operatorType) {
 | 
			
		||||
    case TOKEN_BANG: emitByte(OP_NOT); break;
 | 
			
		||||
    case TOKEN_MINUS: emitByte(OP_NEGATE); break;
 | 
			
		||||
    default: return; // Unreachable.
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -183,31 +199,31 @@ ParseRule rules[] = {
 | 
			
		|||
  [TOKEN_SEMICOLON]     = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_SLASH]         = {NULL,     binary, PREC_FACTOR},
 | 
			
		||||
  [TOKEN_STAR]          = {NULL,     binary, PREC_FACTOR},
 | 
			
		||||
  [TOKEN_BANG]          = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_BANG_EQUAL]    = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_BANG]          = {unary,    NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_BANG_EQUAL]    = {NULL,     binary, PREC_EQUALITY},
 | 
			
		||||
  [TOKEN_EQUAL]         = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_EQUAL_EQUAL]   = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_GREATER]       = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_GREATER_EQUAL] = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_LESS]          = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_LESS_EQUAL]    = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_EQUAL_EQUAL]   = {NULL,     binary, PREC_EQUALITY},
 | 
			
		||||
  [TOKEN_GREATER]       = {NULL,     binary, PREC_COMPARISON},
 | 
			
		||||
  [TOKEN_GREATER_EQUAL] = {NULL,     binary, PREC_COMPARISON},
 | 
			
		||||
  [TOKEN_LESS]          = {NULL,     binary, PREC_COMPARISON},
 | 
			
		||||
  [TOKEN_LESS_EQUAL]    = {NULL,     binary, PREC_COMPARISON},
 | 
			
		||||
  [TOKEN_IDENTIFIER]    = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_STRING]        = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_NUMBER]        = {number,   NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_AND]           = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_TYPE]          = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_ELSE]          = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_FALSE]         = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_FALSE]         = {literal,  NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_FOR]           = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_FN]            = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_IF]            = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_NIL]           = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_NIL]           = {literal,  NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_OR]            = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_PRINT]         = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_RETURN]        = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_SUPER]         = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_THIS]          = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_TRUE]          = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_TRUE]          = {literal,  NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_LET]           = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_WHILE]         = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
  [TOKEN_ERROR]         = {NULL,     NULL,   PREC_NONE},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								src/debug.c
								
								
								
								
							
							
						
						
									
										14
									
								
								src/debug.c
								
								
								
								
							| 
						 | 
				
			
			@ -42,6 +42,18 @@ int disassembleInstruction(Chunk* chunk, int offset) {
 | 
			
		|||
      return simpleInstruction("OP_NEGATE", offset);     
 | 
			
		||||
    case OP_CONSTANT:
 | 
			
		||||
      return constantInstruction("OP_CONSTANT", chunk, offset);
 | 
			
		||||
    case OP_NIL:
 | 
			
		||||
      return simpleInstruction("OP_NIL", offset);
 | 
			
		||||
    case OP_TRUE:
 | 
			
		||||
      return simpleInstruction("OP_TRUE", offset);
 | 
			
		||||
    case OP_FALSE:
 | 
			
		||||
      return simpleInstruction("OP_FALSE", offset);
 | 
			
		||||
    case OP_EQUAL:
 | 
			
		||||
      return simpleInstruction("OP_EQUAL", offset);
 | 
			
		||||
    case OP_GREATER:
 | 
			
		||||
      return simpleInstruction("OP_GREATER", offset);
 | 
			
		||||
    case OP_LESS:
 | 
			
		||||
      return simpleInstruction("OP_LESS", offset);
 | 
			
		||||
    case OP_ADD:
 | 
			
		||||
      return simpleInstruction("OP_ADD", offset);
 | 
			
		||||
    case OP_SUBTRACT:
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +62,8 @@ int disassembleInstruction(Chunk* chunk, int offset) {
 | 
			
		|||
      return simpleInstruction("OP_MULTIPLY", offset);
 | 
			
		||||
    case OP_DIVIDE:
 | 
			
		||||
      return simpleInstruction("OP_DIVIDE", offset);
 | 
			
		||||
    case OP_NOT:
 | 
			
		||||
      return simpleInstruction("OP_NOT", offset);
 | 
			
		||||
    case OP_RETURN:
 | 
			
		||||
      return simpleInstruction("OP_RETURN", offset);
 | 
			
		||||
    default:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								src/value.c
								
								
								
								
							
							
						
						
									
										18
									
								
								src/value.c
								
								
								
								
							| 
						 | 
				
			
			@ -27,5 +27,21 @@ void freeValueArray(ValueArray *array) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void printValue(Value value) {
 | 
			
		||||
  printf("%g", value);
 | 
			
		||||
  switch (value.type) {
 | 
			
		||||
    case VAL_BOOL:
 | 
			
		||||
      printf(AS_BOOL(value) ? "true" : "false");
 | 
			
		||||
      break;
 | 
			
		||||
    case VAL_NIL: printf("nil"); break;
 | 
			
		||||
    case VAL_NUMBER: printf("%g", AS_NUMBER(value)); break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool valuesEqual(Value a, Value b) {
 | 
			
		||||
  if (a.type != b.type) return false;
 | 
			
		||||
  switch (a.type) {
 | 
			
		||||
    case VAL_BOOL:   return AS_BOOL(a) == AS_BOOL(b);
 | 
			
		||||
    case VAL_NIL:    return true;
 | 
			
		||||
    case VAL_NUMBER: return AS_NUMBER(a) == AS_NUMBER(b);
 | 
			
		||||
    default:         return false; // Unreachable.
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										26
									
								
								src/value.h
								
								
								
								
							
							
						
						
									
										26
									
								
								src/value.h
								
								
								
								
							| 
						 | 
				
			
			@ -3,7 +3,30 @@
 | 
			
		|||
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
typedef double Value;
 | 
			
		||||
typedef enum {
 | 
			
		||||
  VAL_BOOL,
 | 
			
		||||
  VAL_NIL, 
 | 
			
		||||
  VAL_NUMBER,
 | 
			
		||||
} ValueType;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  ValueType type;
 | 
			
		||||
  union {
 | 
			
		||||
    bool boolean;
 | 
			
		||||
    double number;
 | 
			
		||||
  } as; 
 | 
			
		||||
} Value;
 | 
			
		||||
 | 
			
		||||
#define BOOL_VAL(value)   ((Value){VAL_BOOL,{.boolean = value}})
 | 
			
		||||
#define NIL_VAL           ((Value){VAL_NIL, {.number = 0}})
 | 
			
		||||
#define NUMBER_VAL(value) ((Value){VAL_NUMBER, {.number = value}}) 
 | 
			
		||||
 | 
			
		||||
#define AS_BOOL(value)   ((value).as.boolean)
 | 
			
		||||
#define AS_NUMBER(value) ((value).as.number) 
 | 
			
		||||
 | 
			
		||||
#define IS_BOOL(value)   ((value).type == VAL_BOOL)
 | 
			
		||||
#define IS_NIL(value)    ((value).type == VAL_NIL)
 | 
			
		||||
#define IS_NUMBER(value) ((value).type == VAL_NUMBER) 
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  int capacity;
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +34,7 @@ typedef struct {
 | 
			
		|||
  Value *values;
 | 
			
		||||
} ValueArray;
 | 
			
		||||
 | 
			
		||||
bool valuesEqual(Value a, Value b);
 | 
			
		||||
void newValueArray(ValueArray *array);
 | 
			
		||||
void writeValueArray(ValueArray *array, Value value);
 | 
			
		||||
void freeValueArray(ValueArray *array);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										64
									
								
								src/vm.c
								
								
								
								
							
							
						
						
									
										64
									
								
								src/vm.c
								
								
								
								
							| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
#include "vm.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
VM vm; 
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +12,19 @@ static void resetStack() {
 | 
			
		|||
  vm.stackTop = vm.stack;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void runtimeError(const char* format, ...) {
 | 
			
		||||
  va_list args;
 | 
			
		||||
  va_start(args, format);
 | 
			
		||||
  vfprintf(stderr, format, args);
 | 
			
		||||
  va_end(args);
 | 
			
		||||
  fputs("\n", stderr);
 | 
			
		||||
 | 
			
		||||
  size_t instruction = vm.ip - vm.chunk->code - 1;
 | 
			
		||||
  int line = vm.chunk->lines[instruction];
 | 
			
		||||
  fprintf(stderr, "[line %d] in script\n", line);
 | 
			
		||||
  resetStack();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void newVM() {
 | 
			
		||||
  resetStack();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -29,14 +43,26 @@ Value pop() {
 | 
			
		|||
  return *vm.stackTop;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Value peek(int distance) {
 | 
			
		||||
  return vm.stackTop[-1 - distance];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool isFalsey(Value value) {
 | 
			
		||||
  return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static InterpretResult run() {
 | 
			
		||||
#define READ_BYTE() (*vm.ip++)
 | 
			
		||||
#define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()])
 | 
			
		||||
#define BINARY_OP(op) \
 | 
			
		||||
#define BINARY_OP(valueType, op) \
 | 
			
		||||
    do { \
 | 
			
		||||
      double b = pop(); \
 | 
			
		||||
      double a = pop(); \
 | 
			
		||||
      push(a op b); \
 | 
			
		||||
      if (!IS_NUMBER(peek(0)) || !IS_NUMBER(peek(1))) { \
 | 
			
		||||
        runtimeError("Operands must be numbers."); \
 | 
			
		||||
        return INTERPRET_RUNTIME_ERROR; \
 | 
			
		||||
      } \
 | 
			
		||||
      double b = AS_NUMBER(pop()); \
 | 
			
		||||
      double a = AS_NUMBER(pop()); \
 | 
			
		||||
      push(valueType(a op b)); \
 | 
			
		||||
    } while (false)
 | 
			
		||||
 | 
			
		||||
  for (;;) {
 | 
			
		||||
| 
						 | 
				
			
			@ -59,11 +85,31 @@ static InterpretResult run() {
 | 
			
		|||
	push(constant);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case OP_ADD:      BINARY_OP(+); break;
 | 
			
		||||
      case OP_SUBTRACT: BINARY_OP(-); break;
 | 
			
		||||
      case OP_MULTIPLY: BINARY_OP(*); break;
 | 
			
		||||
      case OP_DIVIDE:   BINARY_OP(/); break;
 | 
			
		||||
      case OP_NEGATE:   push(-pop()); break;
 | 
			
		||||
      case OP_NIL: push(NIL_VAL); break;
 | 
			
		||||
      case OP_TRUE: push(BOOL_VAL(true)); break;
 | 
			
		||||
      case OP_FALSE: push(BOOL_VAL(false)); break;
 | 
			
		||||
      case OP_EQUAL: {
 | 
			
		||||
        Value b = pop();
 | 
			
		||||
        Value a = pop();
 | 
			
		||||
        push(BOOL_VAL(valuesEqual(a, b)));
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case OP_GREATER:  BINARY_OP(BOOL_VAL, >); break;
 | 
			
		||||
      case OP_LESS:     BINARY_OP(BOOL_VAL, <); break;
 | 
			
		||||
      case OP_ADD:      BINARY_OP(NUMBER_VAL, +); break;
 | 
			
		||||
      case OP_SUBTRACT: BINARY_OP(NUMBER_VAL, -); break;
 | 
			
		||||
      case OP_MULTIPLY: BINARY_OP(NUMBER_VAL, *); break;
 | 
			
		||||
      case OP_DIVIDE:   BINARY_OP(NUMBER_VAL, /); break;
 | 
			
		||||
      case OP_NOT:
 | 
			
		||||
        push(BOOL_VAL(isFalsey(pop())));
 | 
			
		||||
        break;
 | 
			
		||||
      case OP_NEGATE:
 | 
			
		||||
        if (!IS_NUMBER(peek(0))) {
 | 
			
		||||
          runtimeError("Operand must be a number.");
 | 
			
		||||
          return INTERPRET_RUNTIME_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
        push(NUMBER_VAL(-AS_NUMBER(pop())));
 | 
			
		||||
        break;
 | 
			
		||||
      case OP_RETURN: {
 | 
			
		||||
	printValue(pop());
 | 
			
		||||
	printf("\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1 @@
 | 
			
		|||
1 + 2;
 | 
			
		||||
1 + 2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue