Add support for float variables and basic math.
authorDavid Anderson <dvander@alliedmods.net>
Wed Jun 27 02:21:56 2012 -0700 (2012-06-27)
changeset 4633176823669
parent 3 f43e399ab622
child 5 9b63fb7cf5bf
Add support for float variables and basic math.
jitcraft/AST.h
jitcraft/BytecodeCompiler.cpp
jitcraft/BytecodeCompiler.h
jitcraft/BytecodeEmitter.h
jitcraft/Interpreter.cpp
jitcraft/Interpreter.h
jitcraft/Opcodes.cpp
jitcraft/Opcodes.h
jitcraft/Opcodes.tbl
jitcraft/Parser.cpp
jitcraft/Parser.h
jitcraft/Scanner.cpp
jitcraft/Scanner.h
jitcraft/SemanticAnalysis.cpp
jitcraft/SemanticAnalysis.h
jitcraft/Stack.h
jitcraft/Token.h
jitcraft/Types.cpp
jitcraft/Types.h
jitcraft/main.cpp
     1.1 --- a/jitcraft/AST.h	Tue Jun 26 00:58:55 2012 -0700
     1.2 +++ b/jitcraft/AST.h	Wed Jun 27 02:21:56 2012 -0700
     1.3 @@ -29,7 +29,8 @@
     1.4      _(VariableDeclaration)      \
     1.5      _(ForStatement)             \
     1.6      _(ReturnStatement)          \
     1.7 -    _(IntegerLiteralExpression) \
     1.8 +    _(IntegerLiteral)           \
     1.9 +    _(FloatLiteral)             \
    1.10      _(BinaryExpression)         \
    1.11      _(BlockStatement)           \
    1.12      _(Assignment)               \
    1.13 @@ -141,15 +142,20 @@
    1.14      Variable *variable_;
    1.15      Expression *initialization_;
    1.16      ExpressionList *postDimensions_;
    1.17 +    Name *tag_;
    1.18  
    1.19    public:
    1.20 -    VariableDeclaration(Variable *var, ExpressionList *postDimensions, Expression *initialization)
    1.21 +    VariableDeclaration(Variable *var, Name *tag, ExpressionList *postDimensions, Expression *initialization)
    1.22        : variable_(var),
    1.23          postDimensions_(postDimensions),
    1.24 -        initialization_(initialization)
    1.25 +        initialization_(initialization),
    1.26 +        tag_(tag)
    1.27      {
    1.28      }
    1.29  
    1.30 +    Name *tag() const {
    1.31 +        return tag_;
    1.32 +    }
    1.33      Kind kind() const {
    1.34          return kVariableDeclaration;
    1.35      }
    1.36 @@ -197,18 +203,18 @@
    1.37      }
    1.38  };
    1.39  
    1.40 -class IntegerLiteralExpression : public Expression
    1.41 +class IntegerLiteral : public Expression
    1.42  {
    1.43      int value_;
    1.44  
    1.45    public:
    1.46 -    IntegerLiteralExpression(int value)
    1.47 +    IntegerLiteral(int value)
    1.48        : value_(value)
    1.49      {
    1.50      }
    1.51  
    1.52      Kind kind() const {
    1.53 -        return kIntegerLiteralExpression;
    1.54 +        return kIntegerLiteral;
    1.55      }
    1.56      int value() const {
    1.57          return value_;
    1.58 @@ -218,6 +224,27 @@
    1.59      }
    1.60  };
    1.61  
    1.62 +class FloatLiteral : public Expression
    1.63 +{
    1.64 +    double value_;
    1.65 +
    1.66 +  public:
    1.67 +    FloatLiteral(double value)
    1.68 +      : value_(value)
    1.69 +    {
    1.70 +    }
    1.71 +
    1.72 +    Kind kind() const {
    1.73 +        return kFloatLiteral;
    1.74 +    }
    1.75 +    double value() const {
    1.76 +        return value_;
    1.77 +    }
    1.78 +    void accept(AstVisitor *visitor) {
    1.79 +        visitor->visit(this);
    1.80 +    }
    1.81 +};
    1.82 +
    1.83  class BinaryExpression : public Expression
    1.84  {
    1.85      Expression *left_;
     2.1 --- a/jitcraft/BytecodeCompiler.cpp	Tue Jun 26 00:58:55 2012 -0700
     2.2 +++ b/jitcraft/BytecodeCompiler.cpp	Wed Jun 27 02:21:56 2012 -0700
     2.3 @@ -152,12 +152,22 @@
     2.4  }
     2.5  
     2.6  void
     2.7 +BytecodeCompiler::visitForALU(Type *needed, Expression *node)
     2.8 +{
     2.9 +    node->accept(this);
    2.10 +    if (needed->isFloat() && !node->type()->isFloat())
    2.11 +        __ cvt_i2f();
    2.12 +}
    2.13 +
    2.14 +void
    2.15  BytecodeCompiler::visit(BinaryExpression *node)
    2.16  {
    2.17 -    node->left()->accept(this);
    2.18 -    node->right()->accept(this);
    2.19 +    visitForALU(node->type(), node->left());
    2.20 +    visitForALU(node->type(), node->right());
    2.21  
    2.22      Opcode op = TokenToOpcode(node->token());
    2.23 +    if (node->type()->isFloat())
    2.24 +        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
    2.25      __ binary(op);
    2.26  }
    2.27  
    2.28 @@ -256,12 +266,18 @@
    2.29  }
    2.30  
    2.31  void
    2.32 -BytecodeCompiler::visit(IntegerLiteralExpression *node)
    2.33 +BytecodeCompiler::visit(IntegerLiteral *node)
    2.34  {
    2.35      __ int_(node->value());
    2.36  }
    2.37  
    2.38  void
    2.39 +BytecodeCompiler::visit(FloatLiteral *node)
    2.40 +{
    2.41 +    __ float_((float)node->value());
    2.42 +}
    2.43 +
    2.44 +void
    2.45  BytecodeCompiler::visit(VariableDeclaration *node)
    2.46  {
    2.47      Variable *var = node->variable();
     3.1 --- a/jitcraft/BytecodeCompiler.h	Tue Jun 26 00:58:55 2012 -0700
     3.2 +++ b/jitcraft/BytecodeCompiler.h	Wed Jun 27 02:21:56 2012 -0700
     3.3 @@ -57,6 +57,7 @@
     3.4      void leaveScope(Scope *scope);
     3.5      void visitForTest(Expression *expression, BytecodeEmitter::Label *label, bool onTrue);
     3.6      Code *compileFunction(Module *module, FunctionStatement *fun);
     3.7 +    void visitForALU(Type *needed, Expression *node);
     3.8  
     3.9    public:
    3.10      BytecodeCompiler(ParseTree *tree);
    3.11 @@ -71,7 +72,8 @@
    3.12      void visit(ForStatement *node);
    3.13      void visit(BlockStatement *node);
    3.14      void visit(VariableDeclaration *node);
    3.15 -    void visit(IntegerLiteralExpression *node);
    3.16 +    void visit(IntegerLiteral *node);
    3.17 +    void visit(FloatLiteral *node);
    3.18      void visit(ExpressionStatement *node);
    3.19      void visit(FunctionStatement *node);
    3.20      void visit(CallExpression *node);
     4.1 --- a/jitcraft/BytecodeEmitter.h	Tue Jun 26 00:58:55 2012 -0700
     4.2 +++ b/jitcraft/BytecodeEmitter.h	Wed Jun 27 02:21:56 2012 -0700
     4.3 @@ -54,6 +54,10 @@
     4.4          assert(value >= 0 && value <= UCHAR_MAX);
     4.5          *buffer_pos_++ = value;
     4.6      }
     4.7 +    void writeFloat(float value) {
     4.8 +        *(float *)buffer_pos_ = value;
     4.9 +        buffer_pos_ += sizeof(float);
    4.10 +    }
    4.11      void writeInt32(int value) {
    4.12          *(int *)buffer_pos_ = value;
    4.13          buffer_pos_ += sizeof(int);
    4.14 @@ -271,6 +275,14 @@
    4.15      void bounds_sta() {
    4.16          singleByteOp(OP_BOUNDS_STA);
    4.17      }
    4.18 +    void float_(float value) {
    4.19 +        ensure(OP_FLOAT_LENGTH);
    4.20 +        writeOp(OP_FLOAT);
    4.21 +        writeFloat(value);
    4.22 +    }
    4.23 +    void cvt_i2f() {
    4.24 +        singleByteOp(OP_CVT_I2F);
    4.25 +    }
    4.26  };
    4.27  
    4.28  }
     5.1 --- a/jitcraft/Interpreter.cpp	Tue Jun 26 00:58:55 2012 -0700
     5.2 +++ b/jitcraft/Interpreter.cpp	Wed Jun 27 02:21:56 2012 -0700
     5.3 @@ -28,6 +28,12 @@
     5.4          top.sp++;               \
     5.5     } while (0)
     5.6  
     5.7 +#define PUSH_F(top, value)      \
     5.8 +    do {                        \
     5.9 +        top.sp->f = value;      \
    5.10 +        top.sp++;               \
    5.11 +   } while (0)
    5.12 +
    5.13  static inline int
    5.14  POP_I32(Top &top)
    5.15  {
    5.16 @@ -36,6 +42,14 @@
    5.17      return value;
    5.18  }
    5.19  
    5.20 +static inline float
    5.21 +POP_F(Top &top)
    5.22 +{
    5.23 +    float value = top.sp[-1].f;
    5.24 +    top.sp--;
    5.25 +    return value;
    5.26 +}
    5.27 +
    5.28  static inline bool
    5.29  CheckDimensionSize(int size, unsigned width)
    5.30  {
    5.31 @@ -171,7 +185,7 @@
    5.32  }
    5.33  
    5.34  bool
    5.35 -jc::Interpret(Frame *frame, int *result)
    5.36 +jc::Interpret(Frame *frame, LocalSlot *result)
    5.37  {
    5.38      Top &top = *ZONE()->stack().top();
    5.39      LocalSlot *locals = frame->locals();
    5.40 @@ -187,17 +201,19 @@
    5.41      PUSH_I32(top, READ_INT32(top.pc));
    5.42      break;
    5.43  
    5.44 +case OP_FLOAT:
    5.45 +    PUSH_F(top, READ_FLOAT(top.pc));
    5.46 +    break;
    5.47 +
    5.48  case OP_RETURN:
    5.49  {
    5.50 -    int rval = POP_I32(top);
    5.51 -    if (!frame->prev()) {
    5.52 -        *result = rval;
    5.53 +    *result = *--top.sp;
    5.54 +    if (!frame->prev())
    5.55          return true;
    5.56 -    }
    5.57  
    5.58      frame = ZONE()->stack().popFrame(frame);
    5.59      locals = frame->locals();
    5.60 -    PUSH_I32(top, rval);
    5.61 +    *top.sp++ = *result;
    5.62      top.pc += OpcodeInfo[*top.pc].length;
    5.63      continue;
    5.64  }
    5.65 @@ -312,6 +328,44 @@
    5.66      break;
    5.67  }
    5.68  
    5.69 +case OP_ADD_F:
    5.70 +{
    5.71 +    float right = POP_F(top);
    5.72 +    float left = POP_F(top);
    5.73 +    float result = left + right;
    5.74 +    PUSH_F(top, result);
    5.75 +    break;
    5.76 +}
    5.77 +
    5.78 +case OP_SUB_F:
    5.79 +{
    5.80 +    float right = POP_F(top);
    5.81 +    float left = POP_F(top);
    5.82 +    float result = left - right;
    5.83 +    PUSH_F(top, result);
    5.84 +    break;
    5.85 +}
    5.86 +
    5.87 +case OP_MUL_F:
    5.88 +{
    5.89 +    float right = POP_F(top);
    5.90 +    float left = POP_F(top);
    5.91 +    float result = left * right;
    5.92 +    PUSH_F(top, result);
    5.93 +    break;
    5.94 +}
    5.95 +
    5.96 +case OP_DIV_F:
    5.97 +{
    5.98 +    float right = POP_F(top);
    5.99 +    float left = POP_F(top);
   5.100 +    if (!right)
   5.101 +        return false;
   5.102 +    float result = left / right;
   5.103 +    PUSH_F(top, result);
   5.104 +    break;
   5.105 +}
   5.106 +
   5.107  case OP_POP:
   5.108      top.sp--;
   5.109      break;
   5.110 @@ -398,6 +452,14 @@
   5.111      break;
   5.112  }
   5.113  
   5.114 +case OP_CVT_I2F:
   5.115 +{
   5.116 +    int ival = POP_I32(top);
   5.117 +    float fval = (float)ival;
   5.118 +    PUSH_F(top, fval);
   5.119 +    break;
   5.120 +}
   5.121 +
   5.122  default:
   5.123      assert(false);
   5.124      return false;
     6.1 --- a/jitcraft/Interpreter.h	Tue Jun 26 00:58:55 2012 -0700
     6.2 +++ b/jitcraft/Interpreter.h	Wed Jun 27 02:21:56 2012 -0700
     6.3 @@ -22,7 +22,7 @@
     6.4  
     6.5  namespace jc {
     6.6  
     6.7 -bool Interpret(Frame *frame, int *result);
     6.8 +bool Interpret(Frame *frame, LocalSlot *result);
     6.9  
    6.10  // Virtual machine helper functions.
    6.11  UnsafeArray *AllocateUnsafeArray(unsigned width, unsigned ndims, int *dims);
     7.1 --- a/jitcraft/Opcodes.cpp	Tue Jun 26 00:58:55 2012 -0700
     7.2 +++ b/jitcraft/Opcodes.cpp	Wed Jun 27 02:21:56 2012 -0700
     7.3 @@ -55,6 +55,11 @@
     7.4            case OP_SUB:
     7.5            case OP_MUL:
     7.6            case OP_DIV:
     7.7 +          case OP_ADD_F:
     7.8 +          case OP_SUB_F:
     7.9 +          case OP_MUL_F:
    7.10 +          case OP_DIV_F:
    7.11 +          case OP_CVT_I2F:
    7.12            case OP_POP:
    7.13            case OP_LD_STA_I:
    7.14            case OP_LD_STA_P:
    7.15 @@ -70,6 +75,10 @@
    7.16              fprintf(fp, "%d", READ_INT32(pc));
    7.17              break;
    7.18  
    7.19 +          case OP_FLOAT:
    7.20 +            fprintf(fp, "%f", READ_FLOAT(pc));
    7.21 +            break;
    7.22 +
    7.23            case OP_JL:
    7.24            case OP_JLE:
    7.25            case OP_JG:
     8.1 --- a/jitcraft/Opcodes.h	Tue Jun 26 00:58:55 2012 -0700
     8.2 +++ b/jitcraft/Opcodes.h	Wed Jun 27 02:21:56 2012 -0700
     8.3 @@ -80,6 +80,11 @@
     8.4  {
     8.5      return *reinterpret_cast<unsigned *>(pc + 1);
     8.6  }
     8.7 +static inline float
     8.8 +READ_FLOAT(bytecode *pc)
     8.9 +{
    8.10 +    return *reinterpret_cast<float *>(pc + 1);
    8.11 +}
    8.12  
    8.13  class Code;
    8.14  
     9.1 --- a/jitcraft/Opcodes.tbl	Tue Jun 26 00:58:55 2012 -0700
     9.2 +++ b/jitcraft/Opcodes.tbl	Wed Jun 27 02:21:56 2012 -0700
     9.3 @@ -116,3 +116,19 @@
     9.4  // push(array)
     9.5  // push(index)
     9.6  OPDEF(OP_BOUNDS_STA,    28,         "bounds.sta",   1,      2,  2)
     9.7 +
     9.8 +// Pushes a 32-bit IEEE-754 floating point immediate onto the stack.
     9.9 +OPDEF(OP_FLOAT,         29,         "float",        5,      0,  1)
    9.10 +
    9.11 +// Converts an integer to a 32-bit IEEE-754 floating point immediate.
    9.12 +OPDEF(OP_CVT_I2F,       30,         "cvt.i2f",      1,      1,  1)
    9.13 +
    9.14 +// Stack transitions for these binary operators:
    9.15 +// rhs = pop()
    9.16 +// lhs = pop()
    9.17 +// push(lhs OP rhs)
    9.18 +OPDEF(OP_ADD_F,         31,         "add.f",        1,      2,  1)
    9.19 +OPDEF(OP_SUB_F,         32,         "sub.f",        1,      2,  1)
    9.20 +OPDEF(OP_MUL_F,         33,         "mul.f",        1,      2,  1)
    9.21 +OPDEF(OP_DIV_F,         34,         "div.f",        1,      2,  1)
    9.22 +
    10.1 --- a/jitcraft/Parser.cpp	Tue Jun 26 00:58:55 2012 -0700
    10.2 +++ b/jitcraft/Parser.cpp	Wed Jun 27 02:21:56 2012 -0700
    10.3 @@ -68,6 +68,25 @@
    10.4      return proxy;
    10.5  }
    10.6  
    10.7 +bool
    10.8 +Parser::matchName(Name **name, TokenKind kind)
    10.9 +{
   10.10 +    assert(kind == TOK_NAME || kind == TOK_LABEL);
   10.11 +    *name = NULL;
   10.12 +    if (!match(kind))
   10.13 +        return false;
   10.14 +    *name = strings_.add(scanner_.literal());
   10.15 +    return true;
   10.16 +}
   10.17 +
   10.18 +Name *
   10.19 +Parser::expectName()
   10.20 +{
   10.21 +    if (!expect(TOK_NAME))
   10.22 +        return NULL;
   10.23 +    return strings_.add(scanner_.literal());
   10.24 +}
   10.25 +
   10.26  Expression *
   10.27  Parser::primitive()
   10.28  {
   10.29 @@ -79,11 +98,18 @@
   10.30          return bind(name);
   10.31        }
   10.32  
   10.33 +      case TOK_FLOAT_LITERAL:
   10.34 +      {
   10.35 +        scanner_.scan();
   10.36 +        double value = Scanner::ParseDouble(scanner_.literal());
   10.37 +        return new (pool_) FloatLiteral(value);
   10.38 +      }
   10.39 +
   10.40        case TOK_INTEGER_LITERAL:
   10.41        {
   10.42          scanner_.scan();
   10.43          int value = atoi(scanner_.literal());
   10.44 -        return new (pool_) IntegerLiteralExpression(value);
   10.45 +        return new (pool_) IntegerLiteral(value);
   10.46        }
   10.47  
   10.48        default:
   10.49 @@ -326,11 +352,13 @@
   10.50      if (!expect(TOK_NEW))
   10.51          return NULL;
   10.52  
   10.53 -    // Get the name.
   10.54 -    if (!expect(TOK_NAME))
   10.55 +    Name *tag;
   10.56 +    if (matchName(&tag, TOK_LABEL) && !tag)
   10.57          return NULL;
   10.58 -    
   10.59 -    Name *name = strings_.add(scanner_.literal());
   10.60 +
   10.61 +    Name *name = expectName();
   10.62 +    if (!name)
   10.63 +        return NULL;
   10.64  
   10.65      ExpressionList *postDimensions = NULL;
   10.66      if (scanner_.peek() == TOK_LBRACKET) {
   10.67 @@ -359,7 +387,7 @@
   10.68      }
   10.69  
   10.70      Variable *var = scope_->declareVariable(name);
   10.71 -    VariableDeclaration *decl = new (pool_) VariableDeclaration(var, postDimensions, expr);
   10.72 +    VariableDeclaration *decl = new (pool_) VariableDeclaration(var, tag, postDimensions, expr);
   10.73  
   10.74      return decl;
   10.75  }
   10.76 @@ -549,10 +577,7 @@
   10.77          if (scanner_.peek() == TOK_RBRACE)
   10.78              break;
   10.79  
   10.80 -        if (!expect(TOK_NAME))
   10.81 -            return NULL;
   10.82 -
   10.83 -        Name *name = strings_.add(scanner_.literal());
   10.84 +        Name *name = expectName();
   10.85          if (!name)
   10.86              return NULL;
   10.87  
   10.88 @@ -582,9 +607,7 @@
   10.89  Statement *
   10.90  Parser::function()
   10.91  {
   10.92 -    expect(TOK_NAME);
   10.93 -
   10.94 -    Name *name = strings_.add(scanner_.literal());
   10.95 +    Name *name = expectName();
   10.96      if (!name)
   10.97          return NULL;
   10.98  
   10.99 @@ -607,10 +630,7 @@
  10.100          return NULL;
  10.101      if (!match(TOK_RPAREN)) {
  10.102          while (true) {
  10.103 -            if (!expect(TOK_NAME))
  10.104 -                return NULL;
  10.105 -
  10.106 -            Name *name = strings_.add(scanner_.literal());
  10.107 +            Name *name = expectName();
  10.108              if (!name)
  10.109                  return NULL;
  10.110  
  10.111 @@ -783,9 +803,13 @@
  10.112              node->initialization()->accept(this);
  10.113          unindent();
  10.114      }
  10.115 -    void visit(IntegerLiteralExpression *node) {
  10.116 +    void visit(IntegerLiteral *node) {
  10.117          prefix();
  10.118 -        fprintf(fp_, "[ LiteralExpression (%d)\n", node->value());
  10.119 +        fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value());
  10.120 +    }
  10.121 +    void visit(FloatLiteral *node) {
  10.122 +        prefix();
  10.123 +        fprintf(fp_, "[ FloatLiteral (%f)\n", node->value());
  10.124      }
  10.125      void visit(IfStatement *node) {
  10.126          prefix();
    11.1 --- a/jitcraft/Parser.h	Tue Jun 26 00:58:55 2012 -0700
    11.2 +++ b/jitcraft/Parser.h	Wed Jun 27 02:21:56 2012 -0700
    11.3 @@ -45,6 +45,8 @@
    11.4      Scope *enterScope(Scope::Kind kind);
    11.5  
    11.6      VariableDeclaration *variableDeclaration();
    11.7 +    bool matchName(Name **name, TokenKind kind = TOK_NAME);
    11.8 +    Name *expectName();
    11.9      NameProxy *bind(Name *name);
   11.10      Expression *primitive();
   11.11      Expression *call(Expression *callee);
    12.1 --- a/jitcraft/Scanner.cpp	Tue Jun 26 00:58:55 2012 -0700
    12.2 +++ b/jitcraft/Scanner.cpp	Wed Jun 27 02:21:56 2012 -0700
    12.3 @@ -86,21 +86,115 @@
    12.4      return false;
    12.5  }
    12.6  
    12.7 +static inline bool
    12.8 +IsDigit(char c)
    12.9 +{
   12.10 +    return c >= '0' && c <= '9';
   12.11 +}
   12.12 +
   12.13 +// Based off the logic in sc2.c's ftoi()...
   12.14 +double
   12.15 +Scanner::ParseDouble(const char *string)
   12.16 +{
   12.17 +    const char *ptr = string;
   12.18 +
   12.19 +    double number = 0.0;
   12.20 +    while (IsDigit(*ptr)) {
   12.21 +        number = (number * 10) + (*ptr - '0');
   12.22 +        ptr++;
   12.23 +    }
   12.24 +
   12.25 +    assert(*ptr == '.');
   12.26 +    ptr++;
   12.27 +
   12.28 +    double fraction = 0.0;
   12.29 +    double multiplier = 1.0;
   12.30 +    while (IsDigit(*ptr)) {
   12.31 +        fraction = (fraction * 10) + (*ptr - '0');
   12.32 +        multiplier = multiplier / 10.0;
   12.33 +        ptr++;
   12.34 +    }
   12.35 +
   12.36 +    number += fraction * multiplier;
   12.37 +
   12.38 +    if (*ptr++ == 'e') {
   12.39 +        int sign = 1;
   12.40 +        if (*ptr == '-') {
   12.41 +            sign = -1;
   12.42 +            ptr++;
   12.43 +        }
   12.44 +
   12.45 +        int exponent = 0;
   12.46 +        while (IsDigit(*ptr)) {
   12.47 +            exponent = (exponent * 10) + (*ptr - '0');
   12.48 +            ptr++;
   12.49 +        }
   12.50 +
   12.51 +        multiplier = pow(10.0, exponent * sign);
   12.52 +        number *= multiplier;
   12.53 +    }
   12.54 +
   12.55 +    return number;
   12.56 +}
   12.57 +
   12.58  TokenKind
   12.59 -Scanner::integerLiteral(char first)
   12.60 +Scanner::numberLiteral(char first)
   12.61  {
   12.62      literal_ = first;
   12.63  
   12.64 +    char c;
   12.65      for (;;) {
   12.66 -        char c = getChar();
   12.67 -        if (c < '0' || c > '9') {
   12.68 -            putChar(c);
   12.69 +        c = getChar();
   12.70 +        if (!IsDigit(c))
   12.71              break;
   12.72 -        }
   12.73          literal_ += c;
   12.74      }
   12.75  
   12.76 -    return TOK_INTEGER_LITERAL;
   12.77 +    if (c != '.') {
   12.78 +        putChar(c);
   12.79 +        return TOK_INTEGER_LITERAL;
   12.80 +    }
   12.81 +    literal_ += c;
   12.82 +
   12.83 +    c = getChar();
   12.84 +    if (!IsDigit(c)) {
   12.85 +        assert(false);
   12.86 +        return TOK_ERROR;
   12.87 +    }
   12.88 +    literal_ += c;
   12.89 +
   12.90 +    for (;;) {
   12.91 +        c = getChar();
   12.92 +        if (!IsDigit(c))
   12.93 +            break;
   12.94 +        literal_ += c;
   12.95 +    }
   12.96 +
   12.97 +    if (c != 'e') {
   12.98 +        putChar(c);
   12.99 +    } else {
  12.100 +        literal_ += c;
  12.101 +        c = getChar();
  12.102 +        if (c == '-') {
  12.103 +            literal_ += c;
  12.104 +            c = getChar();
  12.105 +        }
  12.106 +        if (!IsDigit(c)) {
  12.107 +            assert(false);
  12.108 +            return TOK_ERROR;
  12.109 +        }
  12.110 +        literal_ += c;
  12.111 +        for (;;) {
  12.112 +            c = getChar();
  12.113 +            if (!IsDigit(c)) {
  12.114 +                putChar(c);
  12.115 +                break;
  12.116 +            }
  12.117 +            literal_ += c;
  12.118 +        }
  12.119 +    }
  12.120 +
  12.121 +    return TOK_FLOAT_LITERAL;
  12.122  }
  12.123  
  12.124  TokenKind
  12.125 @@ -108,10 +202,12 @@
  12.126  {
  12.127      literal_ = first;
  12.128  
  12.129 +    char c;
  12.130      for (;;) {
  12.131 -        char c = getChar();
  12.132 +        c = getChar();
  12.133          if (!isascii(c) || (!isalnum(c) && c != '_')) {
  12.134 -            putChar(c);
  12.135 +            if (c != ':')
  12.136 +                putChar(c);
  12.137              break;
  12.138          }
  12.139          literal_ += c;
  12.140 @@ -129,7 +225,7 @@
  12.141          return TOK_ELSE;
  12.142      if (literal_ == "enum")
  12.143          return TOK_ENUM;
  12.144 -    return TOK_NAME;
  12.145 +    return (c == ':') ? TOK_LABEL : TOK_NAME;
  12.146  }
  12.147  
  12.148  TokenKind
  12.149 @@ -218,9 +314,10 @@
  12.150  
  12.151            default:
  12.152              if (c >= '0' && c <= '9')
  12.153 -                return integerLiteral(c);
  12.154 +                return numberLiteral(c);
  12.155              if (c == '_' || (isascii(c) && isalpha(c)))
  12.156                  return identifier(c);
  12.157 +            assert(false);
  12.158              return TOK_ERROR;
  12.159          }
  12.160      }
    13.1 --- a/jitcraft/Scanner.h	Tue Jun 26 00:58:55 2012 -0700
    13.2 +++ b/jitcraft/Scanner.h	Wed Jun 27 02:21:56 2012 -0700
    13.3 @@ -38,7 +38,7 @@
    13.4      void putChar(char c);
    13.5      void eatSingleLine();
    13.6      bool eatComment();
    13.7 -    TokenKind integerLiteral(char first);
    13.8 +    TokenKind numberLiteral(char first);
    13.9      TokenKind identifier(char first);
   13.10  
   13.11      TokenKind next();
   13.12 @@ -46,6 +46,8 @@
   13.13    public:
   13.14      Scanner(const char *stream, size_t length);
   13.15  
   13.16 +    static double ParseDouble(const char *string);
   13.17 +
   13.18      TokenKind scan();
   13.19      TokenKind peek();
   13.20      TokenKind last() const {
    14.1 --- a/jitcraft/SemanticAnalysis.cpp	Tue Jun 26 00:58:55 2012 -0700
    14.2 +++ b/jitcraft/SemanticAnalysis.cpp	Wed Jun 27 02:21:56 2012 -0700
    14.3 @@ -80,8 +80,8 @@
    14.4          return true;
    14.5        }
    14.6  
    14.7 -      case AstNode::kIntegerLiteralExpression:
    14.8 -        *out = BoxedPrimitive::Int(expression->toIntegerLiteralExpression()->value());
    14.9 +      case AstNode::kIntegerLiteral:
   14.10 +        *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
   14.11          return true;
   14.12  
   14.13        default:
   14.14 @@ -111,15 +111,29 @@
   14.15      name->setType(name->binding()->type());
   14.16  }
   14.17  
   14.18 +static inline bool
   14.19 +TypeCheck(Type *left, Type *right)
   14.20 +{
   14.21 +    if (!left || !right)
   14.22 +        return false;
   14.23 +
   14.24 +    if (left->isPrimitive()) {
   14.25 +        if (!right->isPrimitive())
   14.26 +            return false;
   14.27 +        return left->primitive() == right->primitive();
   14.28 +    }
   14.29 +
   14.30 +    return false;
   14.31 +}
   14.32 +
   14.33  void
   14.34  SemanticAnalysis::visit(Assignment *node)
   14.35  {
   14.36      node->expression()->accept(this);
   14.37  
   14.38      if (node->lvalue()->isIndexExpression()) {
   14.39 -        node->lvalue()->accept(this);
   14.40 -      
   14.41 -        node->setType(node->lvalue()->type());
   14.42 +        node->lvalue()->accept(this);      
   14.43 +        node->setType(node->lvalue()->type()->contained());
   14.44      } else {
   14.45          NameProxy *proxy = node->lvalue()->toNameProxy();
   14.46          if (!proxy->binding()->kind() == BoundName::VARIABLE) {
   14.47 @@ -130,11 +144,37 @@
   14.48          Variable *var = proxy->binding()->toVariable();
   14.49          node->setType(var->type());
   14.50      }
   14.51 +
   14.52 +    assert(TypeCheck(node->type(), node->expression()->type()));
   14.53  }
   14.54  
   14.55 +
   14.56  void
   14.57  SemanticAnalysis::visit(BinaryExpression *node)
   14.58  {
   14.59 +    node->left()->accept(this);
   14.60 +    node->right()->accept(this);
   14.61 +
   14.62 +    if (node->token() >= TOK_PLUS && node->token() <= TOK_SLASH) {
   14.63 +        // Both sides must be primitive.
   14.64 +        Type *left = node->left()->type();
   14.65 +        Type *right = node->right()->type();
   14.66 +        if (!left || !right)
   14.67 +            return;
   14.68 +
   14.69 +        // If either side is a float, the other side must be a float or int.
   14.70 +        if (left->isFloat() || right->isFloat()) {
   14.71 +            assert(left->isFloat() || left->isInt());
   14.72 +            assert(right->isFloat() || right->isInt());
   14.73 +            node->setType(left->isFloat() ? left : right);
   14.74 +            return;
   14.75 +        }
   14.76 +
   14.77 +        // Otherwise, both sides must be integer.
   14.78 +        assert(left->isInt() && right->isInt());
   14.79 +        node->setType(left);
   14.80 +        return;
   14.81 +    }
   14.82  }
   14.83  
   14.84  void
   14.85 @@ -169,9 +209,7 @@
   14.86  void
   14.87  SemanticAnalysis::visit(VariableDeclaration *node)
   14.88  {
   14.89 -    Tag *tag = NULL;
   14.90 -
   14.91 -    Type *type = Type::NewPrimitive(tag);
   14.92 +    Type *type = Type::NewPrimitive(node->tag());
   14.93      if (!type)
   14.94          return;
   14.95  
   14.96 @@ -191,8 +229,8 @@
   14.97              }
   14.98  
   14.99              int size = -1;
  14.100 -            if (expr->isIntegerLiteralExpression()) {
  14.101 -                size = expr->toIntegerLiteralExpression()->value();
  14.102 +            if (expr->isIntegerLiteral()) {
  14.103 +                size = expr->toIntegerLiteral()->value();
  14.104                  if (size <= 0) {
  14.105                      error();
  14.106                      return;
  14.107 @@ -211,7 +249,7 @@
  14.108  }
  14.109  
  14.110  void
  14.111 -SemanticAnalysis::visit(IntegerLiteralExpression *node)
  14.112 +SemanticAnalysis::visit(IntegerLiteral *node)
  14.113  {
  14.114      Type *type = Type::NewPrimitive(NULL);
  14.115      node->setType(type);
  14.116 @@ -259,12 +297,8 @@
  14.117  void
  14.118  SemanticAnalysis::visit(EnumStatement *node)
  14.119  {
  14.120 -    Tag *tag = NULL;
  14.121 -    if (node->name()) {
  14.122 -        tag = new Tag(node->name());
  14.123 -        if (!tag)
  14.124 -            return;
  14.125 -    }
  14.126 +    // :TODO: test "enum Float { ..."
  14.127 +    Name *tag = node->name();
  14.128  
  14.129      Type *type = Type::NewPrimitive(tag);
  14.130      if (!type)
  14.131 @@ -288,3 +322,13 @@
  14.132          value++;
  14.133      }
  14.134  }
  14.135 +
  14.136 +void
  14.137 +SemanticAnalysis::visit(FloatLiteral *node)
  14.138 +{
  14.139 +    Type *type = Type::NewPrimitive(PrimitiveType_Float);
  14.140 +    if (!type)
  14.141 +        return;
  14.142 +
  14.143 +    node->setType(type);
  14.144 +}
    15.1 --- a/jitcraft/SemanticAnalysis.h	Tue Jun 26 00:58:55 2012 -0700
    15.2 +++ b/jitcraft/SemanticAnalysis.h	Wed Jun 27 02:21:56 2012 -0700
    15.3 @@ -47,13 +47,14 @@
    15.4      void visit(ForStatement *node);
    15.5      void visit(BlockStatement *node);
    15.6      void visit(VariableDeclaration *node);
    15.7 -    void visit(IntegerLiteralExpression *node);
    15.8 +    void visit(IntegerLiteral *node);
    15.9      void visit(ExpressionStatement *node);
   15.10      void visit(FunctionStatement *node);
   15.11      void visit(CallExpression *node);
   15.12      void visit(IfStatement *node);
   15.13      void visit(IndexExpression *node);
   15.14      void visit(EnumStatement *node);
   15.15 +    void visit(FloatLiteral *node);
   15.16  };
   15.17  
   15.18  } // namespace jc
    16.1 --- a/jitcraft/Stack.h	Tue Jun 26 00:58:55 2012 -0700
    16.2 +++ b/jitcraft/Stack.h	Wed Jun 27 02:21:56 2012 -0700
    16.3 @@ -28,6 +28,7 @@
    16.4  union LocalSlot
    16.5  {
    16.6      int i32;
    16.7 +    float f;
    16.8      void *p;
    16.9      UnsafeArray *unsafeArray;
   16.10  };
    17.1 --- a/jitcraft/Token.h	Tue Jun 26 00:58:55 2012 -0700
    17.2 +++ b/jitcraft/Token.h	Wed Jun 27 02:21:56 2012 -0700
    17.3 @@ -27,9 +27,11 @@
    17.4      _(RETURN,             "'return'")                   \
    17.5      _(NAME,               "<name>")                     \
    17.6      _(INTEGER_LITERAL,    "<integer>")                  \
    17.7 +    _(FLOAT_LITERAL,      "<float>")                    \
    17.8      _(IF,                 "<if>")                       \
    17.9      _(ELSE,               "<else>")                     \
   17.10      _(ENUM,               "<enum>")                     \
   17.11 +    _(LABEL,              "<label>")                    \
   17.12      _(PLUS,               "+")                          \
   17.13      _(MINUS,              "-")                          \
   17.14      _(STAR,               "*")                          \
    18.1 --- a/jitcraft/Types.cpp	Tue Jun 26 00:58:55 2012 -0700
    18.2 +++ b/jitcraft/Types.cpp	Wed Jun 27 02:21:56 2012 -0700
    18.3 @@ -19,19 +19,27 @@
    18.4  
    18.5  using namespace jc;
    18.6  
    18.7 -Tag::Tag(Name *name)
    18.8 -  : name_(name)
    18.9 -{
   18.10 -}
   18.11 -
   18.12  Type *
   18.13 -Type::NewPrimitive(Tag *tag)
   18.14 +Type::NewPrimitive(Name *tag)
   18.15  {
   18.16      Type *type = new Type;
   18.17      type->kind_ = PRIMITIVE;
   18.18      type->tag_ = tag;
   18.19      
   18.20 -    type->primitive_ = PrimitiveType_Int32;
   18.21 +    if (tag && strcmp(tag, "Float") == 0)
   18.22 +        type->primitive_ = PrimitiveType_Float;
   18.23 +    else
   18.24 +        type->primitive_ = PrimitiveType_Int32;
   18.25 +    return type;
   18.26 +}
   18.27 +
   18.28 +Type *
   18.29 +Type::NewPrimitive(PrimitiveType prim)
   18.30 +{
   18.31 +    Type *type = new Type;
   18.32 +    type->kind_ = PRIMITIVE;
   18.33 +    type->tag_ = NULL;
   18.34 +    type->primitive_ = prim;
   18.35      return type;
   18.36  }
   18.37  
    19.1 --- a/jitcraft/Types.h	Tue Jun 26 00:58:55 2012 -0700
    19.2 +++ b/jitcraft/Types.h	Wed Jun 27 02:21:56 2012 -0700
    19.3 @@ -22,22 +22,10 @@
    19.4  
    19.5  namespace jc {
    19.6  
    19.7 -// Tags are a weak form of user-created types.
    19.8 -class Tag
    19.9 -{
   19.10 -    Name *name_;
   19.11 -
   19.12 -  public:
   19.13 -    Tag(Name *name);
   19.14 -
   19.15 -    Name *name() const {
   19.16 -        return name_;
   19.17 -    }
   19.18 -};
   19.19 -
   19.20  enum PrimitiveType
   19.21  {
   19.22 -    PrimitiveType_Int32
   19.23 +    PrimitiveType_Int32,
   19.24 +    PrimitiveType_Float
   19.25  };
   19.26  
   19.27  class Type
   19.28 @@ -51,7 +39,8 @@
   19.29      static const int UNKNOWN_SIZE = -1;
   19.30      static const size_t MAX_UNSAFE_ARRAY_DEPTH = 5;
   19.31  
   19.32 -    static Type *NewPrimitive(Tag *tag);
   19.33 +    static Type *NewPrimitive(Name *tag);
   19.34 +    static Type *NewPrimitive(PrimitiveType type);
   19.35      static Type *NewUnsafeArray(Type *contained, int elements);
   19.36  
   19.37      bool isPrimitive() const {
   19.38 @@ -86,12 +75,18 @@
   19.39              temp = temp->contained();
   19.40          return temp;
   19.41      }
   19.42 +    bool isFloat() const {
   19.43 +        return isPrimitive() && primitive() == PrimitiveType_Float;
   19.44 +    }
   19.45 +    bool isInt() const {
   19.46 +        return isPrimitive() && primitive() == PrimitiveType_Int32;
   19.47 +    }
   19.48  
   19.49    private:
   19.50      Kind kind_;
   19.51  
   19.52      // If a primitive type, these tell the kind of type.
   19.53 -    Tag *tag_;
   19.54 +    Name *tag_;
   19.55      PrimitiveType primitive_;
   19.56  
   19.57      // The contained type of an array.
    20.1 --- a/jitcraft/main.cpp	Tue Jun 26 00:58:55 2012 -0700
    20.2 +++ b/jitcraft/main.cpp	Wed Jun 27 02:21:56 2012 -0700
    20.3 @@ -92,11 +92,11 @@
    20.4      if (!frame)
    20.5          return false;
    20.6  
    20.7 -    int result;
    20.8 +    LocalSlot result;
    20.9      if (!Interpret(frame, &result))
   20.10          return false;
   20.11  
   20.12 -    printf("Result: %d\n", result);
   20.13 +    printf("Result: %f\n", result.f);
   20.14  
   20.15      return true;
   20.16  }