private Operation readFunctionType(TokenList tokens) {

    Token token;
    Operation operation = new Operation(OP_TYPE);

    if (!tokens.hasNext()) {
      // report error;
      return null;
    }
    token = tokens.next();

    if (token.getType() != TT_RESERVED) {
      // report error
      return null;
    }

    operation.setValue(token.getValue());
    if (!tokens.hasNext()) {
      return operation;
    }

    token = tokens.next();
    if (token.getType() == TT_STAR) {
      // wrap simple type with type-ptr operation
      Operation tmp = operation;
      operation = new Operation(OP_TYPEPTR);
      operation.addOperand(tmp);
    } else {
      tokens.back();
    }

    return operation;
  }
  public Operation readBlock(TokenList tokens) {
    Operation operation = new Operation(OP_BLOCK);
    Token token;

    if (!tokens.hasNext()) {
      // report error
      return null;
    }
    token = tokens.next();
    if (token.getType() != TT_CBRACEL) {
      // report error
      return null;
    }

    OperatorReader opReader = new OperatorReader();

    while (true) {
      Operation operator = opReader.readOperator(tokens);
      if (operator == null) {
        break;
      }
      operation.addOperand(operator);
    }

    // ??? check TT_CBRACER

    return operation;
  }
  private Operation readFunctionName(TokenList tokens) {
    Operation operation = new Operation(OP_VAR);
    Token token;

    if (!tokens.hasNext()) {
      // report error
      return null;
    }

    token = tokens.next();
    if (token.getType() != TT_IDENTIFIER) {
      // report error
      return null;
    }

    operation.setValue(token.getValue());
    return operation;
  }
  private Operation readFunctionParameters(TokenList tokens) {
    Operation operation = new Operation(OP_FUNCPARAMS);
    Token token;

    if (!tokens.hasNext()) {
      // report error, "(" expected
      return null;
    }
    token = tokens.next();
    if (token.getType() != TT_RBRACEL) {
      // report error, "(" expected
      return null;
    }

    if (!tokens.hasNext()) {
      // report error
      return null;
    }
    token = tokens.next();

    if (token.getType() == TT_RBRACER) {
      // empty params list
      return operation;
    }

    Operation params = new Operation(OP_FUNCPARAMS);

    while (true) {

      Operation param = new Operation(OP_FUNCPARAM);
      Operation type = new Operation(OP_TYPE);
      Operation identifier = new Operation(OP_VAR);

      if (token.getType() != TT_IDENTIFIER) {
        // report error
        return null;
      }

      type.setValue(token.getValue());

      if (!tokens.hasNext()) {
        // report error
        return null;
      }
      token = tokens.next();

      if (token.getType() == TT_STAR) {
        Operation ptr = new Operation();
        ptr.addOperand(type);
        type = ptr;
        if (!tokens.hasNext()) {
          // report error
          return null;
        }
        token = tokens.next();
      }
      param.addOperand(type);

      if (token.getType() != TT_IDENTIFIER) {
        // report error
        return null;
      }
      identifier.setValue(token.getValue());
      param.addOperand(identifier);
      params.addOperand(param);

      if (!tokens.hasNext()) {
        // report error
        return null;
      }
      token = tokens.next();

      if (token.getType() == TT_RBRACER) {
        break; // end of parameter definition
      }

      if (token.getType() != TT_COMMA) {
        // report error
        return null;
      }

      if (!tokens.hasNext()) {
        // report error
        return null;
      }
      token = tokens.next();
    }

    operation.addOperand(params);
    return operation;
  }