static Value* subscriptVector(Value* val, const char** expr, parser_cb* cb) { /* Move past the '[' character */ (*expr)++; /* Parse inside of brackets */ Value* index = Value_parse(expr, 0, ']', cb); if(index->type == VAL_ERR) { Value_free(val); return index; } /* Use builtin function from vector.c */ TP(tp); return TP_FILL(tp, "@elem(@@, @@)", val, index); }
static Expression* parseExpr(const char** expr) { Variable* var; Value* val = Value_parse(expr, 0, 0); if(val->type == VAL_END) { var = VarErr(ignoreError()); } else if(val->type == VAL_ERR) { Error* err = Error_copy(val->err); var = VarErr(err); } else { var = VarValue(NULL, Value_copy(val)); } Value_free(val); return Expression_new(var); }
Value* Value_next(const char** expr, char end, parser_cb* cb) { Value* ret; trimSpaces(expr); if(**expr == end) { return ValEnd(); } if(getSign(expr) == -1) { return ValNeg(); } trimSpaces(expr); if(isdigit(**expr) || **expr == '.') { ret = parseNum(expr); } else if(**expr == '(') { (*expr)++; ret = Value_parse(expr, 0, ')', cb); } else if(**expr == '<') { (*expr)++; ret = Vector_parse(expr, cb); } else if(**expr == '|') { (*expr)++; Value* val = Value_parse(expr, 0, '|', cb); /* Error checking */ if(val->type == VAL_ERR) { return val; } /* Use absolute value builtin */ TP(tp); ret = TP_FILL(tp, "@abs(@@)", val); } else if(**expr == '@') { /* Invoke callback to handle special value */ ret = cb->func(expr, cb->data); } else { ret = parseToken(expr, cb); } /* Check if a parse error occurred */ if(ret->type == VAL_ERR) { return ret; } while(1) { bool again = true; Value* tmp = NULL; trimSpaces(expr); switch(**expr) { case '[': tmp = subscriptVector(ret, expr, cb); break; case '(': tmp = callFunc(ret, expr, cb); break; default: again = false; break; } if(!again || tmp == ret) { break; } if(tmp->type == VAL_ERR) { return tmp; } ret = tmp; } /* Check for unary signs afterwards */ while(**expr == '!') { (*expr)++; trimSpaces(expr); ret = ValUnary(UnOp_new(UN_FACT, ret)); } return ret; }
Expression* Expression_parse(const char** expr) { Expression* ret = NULL; Variable* var; Value* val; const char* equals = strchr(*expr, '='); if(equals == NULL) { /* No assignment, just a plain expression. */ return parseExpr(expr); } /* There is an assignment */ /* First, parse the right side of the assignment */ equals++; val = Value_parse(&equals, 0, 0); if(val->type == VAL_ERR) { /* A parse error occurred */ var = VarErr(Error_copy(val->err)); Value_free(val); return Expression_new(var); } if(val->type == VAL_END) { /* Empty input */ Value_free(val); var = VarErr(earlyEnd()); return Expression_new(var); } /* Now parse the left side */ char* name = nextToken(expr); if(name == NULL) { Value_free(val); var = VarErr(syntaxError("No variable to assign to.")); return Expression_new(var); } trimSpaces(expr); if(**expr == '(') { /* Defining a function */ (*expr)++; /* Array of argument names */ unsigned size = 2; char** args = fmalloc(size * sizeof(*args)); unsigned len = 0; /* Add each argument name to the array */ char* arg = nextToken(expr); if(arg == NULL && **expr != ')') { /* Invalid character */ Value_free(val); free(args); free(name); var = VarErr(badChar(**expr)); return Expression_new(var); } trimSpaces(expr); if(arg == NULL) { /* Empty parameter list means function with no args */ free(args); args = NULL; len = 0; } else { /* Loop through each argument in the list */ while(**expr == ',' || **expr == ')') { args[len++] = arg; if(**expr == ')') break; (*expr)++; /* Expand argument array if it's too small */ if(len >= size) { size *= 2; args = frealloc(args, size * sizeof(*args)); } arg = nextToken(expr); if(arg == NULL) { /* Invalid character */ Value_free(val); free(name); /* Free argument names and return */ unsigned i; for(i = 0; i < len; i++) { free(args[i]); } free(args); var = VarErr(badChar(**expr)); return Expression_new(var); } trimSpaces(expr); } } if(**expr != ')') { /* Invalid character inside argument name list */ Value_free(val); free(name); /* Free argument names and return */ unsigned i; for(i = 0; i < len; i++) { free(args[i]); } free(args); var = VarErr(badChar(**expr)); return Expression_new(var); } /* Skip closing parenthesis */ (*expr)++; trimSpaces(expr); if(**expr != '=') { Value_free(val); free(name); unsigned i; for(i = 0; i < len; i++) { free(args[i]); } free(args); var = VarErr(badChar(**expr)); return Expression_new(var); } /* Construct function and return it */ Function* func = Function_new(len, args, val); var = VarFunc(name, func); free(name); ret = Expression_new(var); } else { /* Defining a variable */ if(**expr != '=') { /* In-place manipulation */ BINTYPE bin = BinOp_nextType(expr, 0, 0); /* Still not an equals sign means invalid character */ if(**expr != '=') { Value_free(val); free(name); var = VarErr(badChar(**expr)); return Expression_new(var); } val = ValExpr(BinOp_new(bin, ValVar(name), val)); } var = VarValue(name, val); free(name); ret = Expression_new(var); } return ret; }