Exemple #1
0
/* Parse a placeholder from a format string */
Placeholder* Placeholder_parse(const char** expr) {
	if(**expr != '@') {
		RAISE(badChar(**expr), true);
	}
	
	/* Move past '@' */
	(*expr)++;
	
	unsigned index = 0;
	if(isdigit(**expr)) {
		/* Like @1v or @4@ */
		char* end;
		errno = 0;
		
		/* Read the number after the '@' */
		index = (unsigned)strtoul(*expr, &end, 10);
		if(errno != 0 || index == 0 || *expr == end) {
			/* An error occurred (EINVAL, ERANGE) */
			RAISE(syntaxError("Invalid number in placeholder"), true);
		}
		
		/* Advance past the number */
		*expr = end;
	}
	
	PLACETYPE type = getPlaceholderType(**expr);
	if(type == PH_ERR) {
		RAISE(badChar(**expr), true);
	}
	
	(*expr)++;
	
	return Placeholder_new(type, index);
}
 void validateQuotedLocal()
 {
     ++finger;
     while(*finger != '"')
     {
         if(*finger == '\\')
         {
             ++finger;
             if(!*finger)
                 fail("unexpected end-of-string in quoted local part");
             else if(badChar(*finger))
                 fail("illegal escaped character in quoted local part");
         }
         else if(!*finger)
             fail("unexpected end-of-string in quoted local part");
         else if(badQuotedChar(*finger))
             fail("illegal character in quoted local part (may need escaping)");
         ++finger;
     }
     ++finger;
     if(!*finger)
         fail("address had quoted local part but no domain (reached end-of-string)");
     else if(*finger != '@')
         fail("quoted local part was not followed by @");
     ++finger;
 }
Exemple #3
0
static Value* parseToken(const char** expr, parser_cb* cb) {
	Value* ret;
	
	char* token = nextToken(expr);
	if(token == NULL) {
		return ValErr(badChar(**expr));
	}
	
	trimSpaces(expr);
	if(**expr == '(') {
		(*expr)++;
		ArgList* arglist = ArgList_parse(expr, ',', ')', cb);
		if(arglist == NULL) {
			/* Parse error occurred and has already been raised */
			free(token);
			return ValErr(ignoreError());
		}
		
		ret = ValCall(FuncCall_create(token, arglist));
	}
	else {
		ret = ValVar(token);
	}
	
	free(token);
	return ret;
}
Exemple #4
0
static Value* parseNum(const char** expr) {
	Value* ret;
	char* end1;
	char* end2;
	
	errno = 0;
	double dbl = strtod(*expr, &end1);
	if(errno != 0 || *expr == end1) {
		/* An error occurred (EINVAL, ERANGE) */
		end1 = NULL;
	}
	
	long long ll = strtoll(*expr, &end2, 10);
	if(errno != 0 || *expr == end2) {
		/* An error occurred (EINVAL, ERANGE) */
		end2 = NULL;
	}
	
	if(end1 > end2) {
		/* Must be a double because more of the string was parsed as double than long long */
		ret = ValReal(dbl);
		*expr = end1;
	}
	else if(end2 != NULL) {
		/* Must be an integer */
		ret = ValInt(ll);
		*expr = end2;
	}
	else {
		/* Both failed to convert the data */
		ret = ValErr(badChar(**expr));
	}
	
	return ret;
}
 void validateValue(char const * _value, char const * _label)
 {
     value = finger = _value;
     label = _label;
     while(*finger)
     {
         if(badChar(*finger))
             fail("illegal character");
         ++finger;
     }
 }
 void escapeQuoted(char const * in, StringBuffer & out, char const * _label)
 {
     value = finger = in;
     label = _label;
     while(*finger)
     {
         if(badChar(*finger))
             fail("illegal character");
         else if((*finger == '"') || (*finger == '\\'))
         {
             if(finger>in)
                 out.append(finger-in, in);
             out.append('\\');
             in = finger;
         }
         ++finger;
     }
     if(finger>in)
         out.append(finger-in, in);
 }
Exemple #7
0
int main(int argc, char* argv[]) {
	Context* ctx = Context_new();
	register_math(ctx);
	
	for(nextLine(); !feof(stdin); nextLine()) {
		/* Strip trailing newline */
		char* end;
		if((end = strchr(line, '\n')) != NULL) *end = '\0';
		if((end = strchr(line, '\r')) != NULL) *end = '\0';
		if((end = strchr(line, '#')) != NULL) *end = '\0';
		
		const char* p = line;
		
		/* Get verbosity level */
		int verbose = 0;
		while(p[0] == '?') {
			verbose++;
			p++;
		}
		trimSpaces(&p);
		
		if(*p == '~') {
			/* Variable deletion */
			p++;
			
			char* name = nextToken(&p);
			if(name == NULL) {
				/* '~~~' means reset interpreter */
				if(p[0] == '~' && p[1] == '~') {
					/* Wipe out context */
					Context_free(ctx);
					ctx = Context_new();
					register_math(ctx);
					continue;
				}
				
				if(*p == '\0') {
					RAISE(earlyEnd());
					continue;
				}
				
				RAISE(badChar(*p));
				continue;
			}
			
			Context_del(ctx, name);
			
			free(name);
			
			continue;
		}
		
		/* Parse the user's input */
		Expression* expr = Expression_parse(&p);
		
		/* Print expression depending on verbosity */
		Expression_print(expr, ctx, verbose);
		
		/* Error? Go to next loop iteration */
		if(Expression_didError(expr)) {
			Expression_free(expr);
			continue;
		}
		
		/* Evaluate expression */
		Value* result = Expression_eval(expr, ctx);
		Expression_free(expr);
		
		/* Print result */
		Value_print(result, ctx);
		
		Value_free(result);
	}
	
	Context_free(ctx);
	
	return 0;
}
Exemple #8
0
/* By default, the '@' character is illegal */
Value* _default_cb(const char** expr, void* data) {
	return ValErr(badChar(**expr));
}
Exemple #9
0
Value* Value_parse(const char** expr, char sep, char end, parser_cb* cb) {
	Value* val;
	BINTYPE op = BIN_UNK;
	BinOp* tree = NULL;
	BinOp* prev;
	
	while(1) {
		/* Get next value */
		val = Value_next(expr, end, cb);
		
		/* Error parsing next value? */
		if(val->type == VAL_ERR) {
			if(tree) {
				BinOp_free(tree);
			}
			
			return val;
		}
		
		/* End of input? */
		if(val->type == VAL_END) {
			if(tree) {
				BinOp_free(tree);
			}
			
			return val;
		}
		
		/* Special case: negative value */
		if(val->type == VAL_NEG) {
			Value_free(val);
			
			BinOp* cur = BinOp_new(BIN_MUL, ValInt(-1), NULL);
			
			if(tree) {
				prev->b = ValExpr(cur);
			}
			else {
				tree = cur;
			}
			
			prev = cur;
			continue;
		}
		
		/* Get next operator if it exists */
		op = BinOp_nextType(expr, sep, end);
		
		/* Invalid operator? Return syntax error */
		if(op == BIN_UNK) {
			/* Exit gracefully and return error */
			if(tree) {
				BinOp_free(tree);
			}
			
			Value_free(val);
			return ValErr(badChar(**expr));
		}
		/* End of the statement? */
		else if(op == BIN_END) {
			/* Only skip end character if there's only one value to parse */
			if(!sep && **expr && **expr == end) {
				(*expr)++;
			}
			
			/* If there was only one value, return it */
			if(!tree) {
				return val;
			}
			
			/* Otherwise, place the final value into the tree and break out of the parse loop */
			prev->b = val;
			break;
		}
		
		/* Tree not yet begun? Initialize it! */
		if(tree == NULL) {
			tree = BinOp_new(op, val, NULL);
			prev = tree;
		}
		else {
			/* Tree already started, so add to it */
			treeAddValue(&tree, &prev, op, val);
		}
	}
	
	return ValExpr(tree);
}
Exemple #10
0
VERBOSITY getVerbosity(const char** str) {
	VERBOSITY ret = 0;
	
	if(**str != '?') {
		return 0;
	}
	
	/* Move past the '?' */
	(*str)++;
	
	bool again = true;
	while(again) {
		switch(**str) {
#define ADD_V(lvl) do { \
	if(ret & V_##lvl) { \
		RAISE(syntaxError("Specified " #lvl " verbosity more than once."), false); \
		return V_ERR; \
	} \
	ret |= V_##lvl; \
} while(0)
			
			case VC_REPR:
				ADD_V(REPR);
				break;
			
			case VC_PRETTY:
				ADD_V(PRETTY);
				/* Pretty implies repr */
				ret |= V_REPR;
				break;
			
			case VC_WRAP:
				ADD_V(WRAP);
				break;
			
			case VC_TREE:
				ADD_V(TREE);
				break;
			
			case VC_XML:
				ADD_V(XML);
				break;
			
			case ' ':
			case '\t':
				/* Verbosity command ended by whitespace only */
				again = false;
				break;
			
			default:
				RAISE(badChar(**str), false);
				return V_ERR;
		}
		
#undef ADD_V
		
		(*str)++;
	}
	
	/* For slight backwards compatibility and for ease of use */
	if(ret == 0) {
		ret |= V_REPR;
	}
	
	return ret;
}
Exemple #11
0
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;
}