Пример #1
0
int check_do_while(is_do_while* node, is_label* label)
{
	int errors = 0;

	int mylabel = ++label_counter; /* setting label for use with loops and break/continue */

	if (label)
		node->scope = scope_new(symbol_new_loop(label->name, node->line, mylabel), false);
	else
		node->scope = scope_new(symbol_new_loop(NULL, node->line, mylabel), false);
		
	scope_push(node->scope);
		errors += check_stmt(node->body);
		if (errors == 0)
			node->terminates = node->body->terminates;

		errors += check_expr(node->cond);
		if (errors == 0)
		{
			if (!type_native_assign_able(t_type_native_bool, node->cond->s_type))
			{
				errors++;
				pretty_error(node->line, "invalid do..while condition (must be boolean)");
			}
		}
	scope_pop();
	return errors;
}
Пример #2
0
int check_while(is_while* node, is_label* label)
{
	int errors = 0;
	char *string;

	int mylabel = ++label_counter; /* setting label for use with loops and break/continue */
	
	if (label)
		node->scope = scope_new(symbol_new_loop(label->name, node->line, mylabel), false);
	else
		node->scope = scope_new(symbol_new_loop(NULL, node->line, mylabel), false);
		
	scope_push(node->scope);
		errors += check_expr(node->cond);
		if (errors == 0)
		{
			if (!type_native_assign_able(t_type_native_bool, node->cond->s_type))
			{
				errors++;
				pretty_error(node->line, "invalid while condition: expected boolean, got %s", string = string_type_decl(node->cond->s_type));
				free(string);
			}
		}

		errors += check_stmt(node->body);
		node->terminates = node->body->terminates;
	scope_pop();
	
	return errors;
}
Пример #3
0
void test_search_on_parent_scope(CuTest *tc) {
  /* parent */
  scope_new();
  scope_sym_table_insert("a", "A", NULL);
  
  /* new scope */
  scope_new();
  
  CuAssertIntEquals(tc, 2, scope_numbers());
  CuAssertPtrNotNull(tc, scope_search_identifier("a"));
  scope_reset();
}
Пример #4
0
void test_insert_and_retrieve_entry_to_scope(CuTest *tc) {
  scope_new();
  scope_sym_table_insert("a", "A", NULL);
  
  CuAssertPtrNotNull(tc, scope_search_identifier("a"));
  scope_reset();
}
Пример #5
0
static
void
_define_builtin_function(Scope *builtin_scope, Type rtype, char *name, builtin_function fn, int nparams, ...) {
	Symbol *fn_symbol = symbol_new(S_BUILTIN, name);
	fn_symbol->eval_type = rtype;
	fn_symbol->fn = fn;

	scope_define(builtin_scope, fn_symbol);

	fn_symbol->args = scope_new(NULL);
	va_list params;
	va_start(params, nparams);
	for(int i = 0; i < nparams; i++) {
		Type t = va_arg(params, Type);

		/* the n-th parameter is called "n" */
		char buf[32];
		snprintf(buf, 32, "%d", i);

		Symbol *sy = symbol_new(S_VARIABLE, buf);
		sy->eval_type = t;
		scope_define(fn_symbol->args, sy);
	}
	va_end(params);
}
Пример #6
0
void test_create_scope(CuTest *tc) {  
  CuAssertIntEquals(tc, 0, scope_numbers());
  
  scope_new();
  
  CuAssertIntEquals(tc, 1, scope_numbers());
  scope_reset();
}
Пример #7
0
void test_reset_should_have_no_scope(CuTest *tc) {
  scope_new();
  
  CuAssertIntEquals(tc, 1, scope_numbers());
  scope_reset();
    
  CuAssertIntEquals(tc, 0, scope_numbers());
  scope_reset();
}
Пример #8
0
void test_do_not_find_entry_scope(CuTest *tc) {
  scope_new();
  
  CuAssertIntEquals(tc, 1, scope_numbers());
  CuAssertFalse(tc, is_identifier_declared("a"));
  CuAssertPtrNull(tc, scope_search_identifier("a"));
  
  scope_reset();
}
Пример #9
0
int check_for(is_for* node, is_label* label)
{
	int errors = 0, cond_errors;
	char* typeA;

	int mylabel = ++label_counter; /* setting label for use with loops and break/continue */

	if (label)
		node->scope = scope_new(symbol_new_loop(label->name, node->line, mylabel), false);
	else
		node->scope = scope_new(symbol_new_loop(NULL, node->line, mylabel), false);
		
	scope_push(node->scope);
		if (node->init)
			errors += check_for_init(node->init);

		if (node->cond)
		{
			cond_errors = check_for_cond(node->cond);
			if (cond_errors == 0)
			{
				if (!type_native_assign_able(t_type_native_bool, node->cond->s_type))
				{
					cond_errors++;
					pretty_error(node->line, "for conditional is not boolean (is of type %s)", typeA = string_type_decl(node->cond->s_type));
					free(typeA);
				}
			}
			errors += cond_errors;
		}
	
		if (node->inc)
			errors += check_for_inc(node->inc);

		errors += check_stmt(node->body);

		if (errors == 0)
			node->terminates = (node->body ? node->body->terminates : true);
	scope_pop();
 
	return errors;
}
Пример #10
0
int check_switch(is_switch* node)
{
	int errors = 0;
	int mylabel = ++label_counter; /* setting label for use with break */
	char *type;

	if (node->label)
		errors += check_label(node->label);

	errors += check_expr(node->expr);

	if (errors == 0)
	{
		if (node->expr->s_type->type == t_type_decl_array_decl)
		{
			errors++;

			type = string_type_decl(node->expr->s_type);
			pretty_error(node->line, "switch statement expression must be of object type (got %s)", type);
			free(type);
		}
	}

	if (errors == 0)
	{
		if (node->label)
			node->scope = scope_new(symbol_new_switch(node->label->name, node->line, mylabel, node->expr->s_type->data.type_object, symtab->framepos++), false);
		else
			node->scope = scope_new(symbol_new_switch(NULL, node->line, mylabel, node->expr->s_type->data.type_object, symtab->framepos++), false);

		scope_push(node->scope);
			check_switch_stmt_list(node->list, node);

			if (errors == 0)
				node->terminates = (node->list ? node->list->terminates : true);
		scope_pop();
 	}

	return errors;
}
Пример #11
0
Файл: json.c Проект: organix/art
/*
json       = (_ value)+ _
_          = [ \t\n\r\b\f]*
*/
OOP
json_grammar_new()
{
    OOP scope = scope_new(o_empty_scope);
    OOP g_ws = star_pattern_new(
        if_pattern_new(charset_p_new(" \t\n\r\b\f")));
    object_call(scope, s_bind, s_ws, g_ws);
    OOP g_value = value_grammar_new(scope);
    OOP g_json = and_pattern_new(
        plus_pattern_new(
            and_pattern_new(
                g_ws,
                g_value)),
            g_ws);
    object_call(scope, s_bind, s_json, g_json);
    return g_json;
}
Пример #12
0
int generate_for_item(Pool *pool, FILE *out, AstFor *p, ListNode *item, int *need_comma)
{
  Scope *scope = scope_new(pool, p->scope);
  ListBuilder code = list_builder_init(pool);

  if (dynamic_ok(p->filter) &&
    !test_filter(p->filter, ast_to_outline_item(item->d)))
    return 1;

  if (p->list && *need_comma)
    CHECK(file_putc(out, ','));
  *need_comma = 1;

  scope_add(scope, pool, p->item, item->d);
  CHECK(parse_code(pool, &p->code, scope, out_list_builder(&code)));
  CHECK(generate_code(pool, out, code.first));
  return 1;
}
Пример #13
0
struct parser_state *cli_js_init(void)
{
	struct parser_state *state = cli_calloc(1, sizeof(*state));
	if(!state)
		return NULL;
	if(!scope_new(state)) {
		free(state);
		return NULL;
	}
	state->global = state->current;

	if(yylex_init(&state->scanner)) {
		scope_done(state->global);
		free(state);
		return NULL;
	}
	cli_dbgmsg(MODULE "cli_js_init() done\n");
	return state;
}
Пример #14
0
int generate_macro_call(Pool *pool, FILE *out, AstMacroCall *p)
{
  ListNode *call_input;
  ListNode *macro_input;
  Scope *scope = scope_new(pool, p->macro->scope);
  ListBuilder code = list_builder_init(pool);

  /* Assign values to all inputs: */
  macro_input = p->macro->inputs;
  call_input = p->inputs;
  while (macro_input && call_input) {
    AstCodeText *name = macro_input->d.p;
    scope_add(scope, pool, name->code, call_input->d);

    macro_input = macro_input->next;
    call_input = call_input->next;
  }

  CHECK(parse_code(pool, &p->macro->code, scope, out_list_builder(&code)));
  CHECK(generate_code(pool, out, code.first));
  return 1;
}
Пример #15
0
int check_class_def(is_class_def* node)
{
	int errors = 0;
	SYMBOL* symbol;

	symbol = scope_lookup(symtab, node->id->name, t_symbol_class);
	if (symbol)
	{
		errors++;
		pretty_error(node->line, "class \"%s\" is already defined (previous declaration was here: %d)", node->id->name, symbol->line);
	} else
		scope_insert(symtab, symbol = symbol_new_class(node->id->name, node->line));

	node->scope = scope_new(symbol, true);

	/*
		FIXME:
		this should be in application and not in class def,
		because theoretically class should be able to access other classes
	*/
	scope_push(node->scope);
		errors += check_class_stmt_list(node->body, true);

		if (errors == 0)
		{
			symbol = scope_lookup(symtab, "main", t_symbol_func);
			if (!symbol)
			{
				errors++;
				pretty_error(node->line, "missing main entry point");
			}
		}
		errors += check_class_stmt_list(node->body, false);
	scope_pop();

	return errors;
}
Пример #16
0
int check_func_def(is_func_def* node, bool first_pass)
{
	SYMBOL* symbol;
	SCOPE* tempscope;
	int label;
	int errors = 0;
	is_type_decl *tmpType = NULL;

	if (first_pass)
	{
		errors += check_type_decl(node->type);

		symbol = scope_lookup(symtab, node->id->name, t_symbol_func);
		if (symbol)
		{
			pretty_error(node->line, "symbol \"%s\" is already defined (previous declaration was here: %d)", node->id->name, symbol->line);
			errors++;
		} else
		{
			tempscope = scope_new(NULL, false);
			scope_push(tempscope);
				errors += check_func_def_args(node->args);
			scope_pop();
			
			if (strcmp(node->id->name, "main") == 0)
			{
				label = 0;

				if (node->args) /* no args is valid */
				{
					if (node->args->length == 1) /* main may must not have more than two arguments */
					{
						tmpType = insert_type_decl_array(insert_array_decl(insert_type_object(t_type_native_string), new_dims_empty_list(0, 1))); /* must be an array of Strings */

						if (!type_type_equal(tmpType,node->args->node->type))
						{
							errors++;
							pretty_error(node->line, "main function arguments do not match any valid prototypes");
						}

						free_type_decl(tmpType);
					} else
					{
						errors++;
						pretty_error(node->line, "main function arguments do not match any valid prototypes");
					}
				}

				tmpType = insert_type_decl_object(insert_type_object(t_type_native_int)); /* return value must be int or void */

				if (!type_type_equal(tmpType,node->type))
				{
					free_type_decl(tmpType);

					tmpType = new_type_decl_void(0); /* check for void */

					if (!type_type_equal(tmpType,node->type)) /* none; errors occurred */
					{
						errors++;
						pretty_error(node->line, "main function return type does not match any valid types (nor int nor void)");
					}
				}
				
				free_type_decl(tmpType);
			} else
				label = ++label_counter;

			symbol = symbol_new_func(node->id->name, node->line, node->type, node->args, label);
			scope_delete(tempscope);

			scope_insert(symtab, symbol);

			node->scope = scope_new(symbol, false);
		}
	} else
	{
		scope_push(node->scope);
			errors += check_func_def_args(node->args); /* this will not give errors */
			errors += check_stmt_list(node->body);
			
			if ((!node->body || !node->body->terminated) &&
				!(node->type->type == t_type_decl_type_object && node->type->data.type_object->type == t_type_native_void))
			{
				pretty_error(node->line, "reached end of non void function");
				errors++;		
			}
		scope_pop();
	}

	return errors;
}
Пример #17
0
/**
 * Program entry point. Constructs and launches the main program object.
 */
int main(int argc, char *argv[])
{
    Pool pool = pool_init(0x10000); /* 64K block size */
    Options opt = options_init();
    Source *in;
    Scope *scope = scope_new(&pool, 0);
    ListBuilder code = list_builder_init(&pool);

    /* Read the options: */
    if (!options_parse(&opt, argc, argv)) {
        options_usage(argv[0]);
        goto error;
    }

    /* Determine output file name: */
    if (!string_size(opt.name_out)) {
        if (string_rmatch(opt.name_in, string_from_k(".ol")) != 3) {
            fprintf(stderr, "error: If no output file is specified, the input file name must end with \".ol\".\n");
            goto error;
        }
        opt.name_out = string(opt.name_in.p, opt.name_in.end - 3);
    }

    /* Input stream: */
    in = source_load(&pool, opt.name_in);
    if (!in) {
        fprintf(stderr, "error: Could not open source file \"%s\"\n", opt.name_in.p);
        goto error;
    }

    /* Keywords: */
    scope_add(scope, &pool, string_from_k("macro"), dynamic(type_keyword,
              keyword_new(&pool, parse_macro)));
    scope_add(scope, &pool, string_from_k("outline"), dynamic(type_keyword,
              keyword_new(&pool, parse_outline)));
    scope_add(scope, &pool, string_from_k("union"), dynamic(type_keyword,
              keyword_new(&pool, parse_union)));
    scope_add(scope, &pool, string_from_k("map"), dynamic(type_keyword,
              keyword_new(&pool, parse_map)));
    scope_add(scope, &pool, string_from_k("for"), dynamic(type_keyword,
              keyword_new(&pool, parse_for)));
    scope_add(scope, &pool, string_from_k("include"), dynamic(type_keyword,
              keyword_new(&pool, parse_include)));

    /* Do outline2c stuff: */
    if (!parse_code(&pool, in, scope, out_list_builder(&code))) goto error;
    if (opt.debug) {
        printf("--- AST: ---\n");
        dump_code(code.first, 0);
        printf("\n");
    }
    if (!main_generate(&pool, code.first, &opt)) goto error;

    /* Clean up: */
    pool_free(&pool);
    return 0;

error:
    pool_free(&pool);
    return 1;
}
Пример #18
0
/* buffer is html-normlike "chunk", if original file is bigger than buffer,
 * we rewind to a space, so we'll know that tokens won't be broken in half at
 * the end of a buffer. All tokens except string-literals of course.
 * So we can assume that after the buffer there is either a space, EOF, or a
 * chunk of text not containing whitespace at all (for which we care only if its
 * a stringliteral)*/
void cli_js_process_buffer(struct parser_state *state, const char *buf, size_t n)
{
	struct scope* current = state->current;
	YYSTYPE val;
	int yv;
	YY_BUFFER_STATE yyb;

	if(!state->global) {
		/* this state has either not been initialized,
		 * or cli_js_parse_done() was already called on it */
		cli_warnmsg(MODULE "invalid state\n");
		return;
	}
	yyb = yy_scan_bytes(buf, n, state->scanner);
	memset(&val, 0, sizeof(val));
	val.vtype = vtype_undefined;
	/* on EOF yylex will return 0 */
	while( (yv=yylex(&val, state->scanner)) != 0)
	{
		const char *text;
		size_t leng;

		val.type = yv;
		switch(yv) {
			case TOK_VAR:
				current->fsm_state = InsideVar;
				break;
			case TOK_IDENTIFIER_NAME:
				text = yyget_text(state->scanner);
				leng = yyget_leng(state->scanner);
				if(current->last_token == TOK_DOT) {
					/* this is a member name, don't normalize
					*/
					TOKEN_SET(&val, string, cli_strdup(text));
					val.type = TOK_UNNORM_IDENTIFIER;
				} else {
					switch(current->fsm_state) {
						case WaitParameterList:
							state->syntax_errors++;
							/* fall through */
						case Base:
						case InsideInitializer:
							TOKEN_SET(&val, cstring, scope_use(current, text, leng));
							break;
						case InsideVar:
						case InsideFunctionDecl:
							TOKEN_SET(&val, cstring, scope_declare(current, text, leng, state));
							current->fsm_state = InsideInitializer;
							current->brackets = 0;
							break;
						case WaitFunctionName:
							TOKEN_SET(&val, cstring, scope_declare(current, text, leng, state));
							current->fsm_state = WaitParameterList;
							break;
					}
				}
				break;
			case TOK_PAR_OPEN:
				switch(current->fsm_state) {
					case WaitFunctionName:
						/* fallthrough */
					case WaitParameterList:
						current->fsm_state = InsideFunctionDecl;
						break;
					default:
						/* noop */
						break;
				}
				break;
			case TOK_PAR_CLOSE:
				switch(current->fsm_state) {
					case WaitFunctionName:
						state->syntax_errors++;
						break;
					case WaitParameterList:
						current->fsm_state = Base;
						break;
					default:
						/* noop */
						break;
				}
				break;
			case TOK_CURLY_BRACE_OPEN:
				switch(current->fsm_state) {
					case WaitFunctionName:
						/* fallthrough */
					case WaitParameterList:
					case InsideFunctionDecl:
						/* in a syntactically correct
						 * file, we would already be in
						 * the Base state when we see a {
						 */
						current->fsm_state = Base;
						/* fall-through */
					case InsideVar:
					case InsideInitializer:
						state->syntax_errors++;
						/* fall-through */
					case Base:
					default:
						current->blocks++;
						break;
				}
				break;
					case TOK_CURLY_BRACE_CLOSE:
				if(current->blocks > 0)
					current->blocks--;
				else
					state->syntax_errors++;
				if(!current->blocks) {
					if(current->parent) {
						/* add dummy FUNCTION token to
						 * mark function end */
						TOKEN_SET(&val, cstring, "}");
						add_token(state, &val);
						TOKEN_SET(&val, scope, NULL);
						val.type = TOK_FUNCTION;

						state->current = current = current->parent;
					} else{
						/* extra } */
						state->syntax_errors++;
				}
				}
				break;
			case TOK_BRACKET_OPEN:
				current->brackets++;
				break;
			case TOK_BRACKET_CLOSE:
				if(current->brackets > 0)
					current->brackets--;
				else
					state->syntax_errors++;
				break;
			case TOK_COMMA:
				if (current->fsm_state == InsideInitializer && current->brackets == 0 && current->blocks == 0) {
					/* initializer ended only if we
					 * encountered a comma, and [] are
					 * balanced.
					 * This avoids switching state on:
					 * var x = [4,y,u];*/
					current->fsm_state = InsideVar;
				}
				break;
			case TOK_SEMICOLON:
				if (current->brackets == 0 && current->blocks == 0) {
					/* avoid switching state on unbalanced []:
					 * var x = [test;testi]; */
					current->fsm_state = Base;
				}
				break;
			case TOK_FUNCTION:
				current = scope_new(state);
				current->fsm_state = WaitFunctionName;
				TOKEN_SET(&val, scope, state->current);
				break;
			case TOK_StringLiteral:
				if(state->tokens.cnt > 1 && state->tokens.data[state->tokens.cnt-1].type == TOK_PLUS) {
					/* see if can fold */
					yystype *prev_string = &state->tokens.data[state->tokens.cnt-2];
					if(prev_string->type == TOK_StringLiteral) {
						char *str = TOKEN_GET(prev_string, string);
						size_t str_len = strlen(str);

						text = yyget_text(state->scanner);
						leng = yyget_leng(state->scanner);


						/* delete TOK_PLUS */
						free_token(&state->tokens.data[--state->tokens.cnt]);

						str = cli_realloc(str, str_len + leng + 1);
						if (!str)
						    break;
						strncpy(str+str_len, text, leng);
						str[str_len + leng] = '\0';
						TOKEN_SET(prev_string, string, str);
						free(val.val.string);
						memset(&val, 0, sizeof(val));
						val.vtype = vtype_undefined;
						continue;
					}
				}
				break;
		}
		if(val.vtype == vtype_undefined) {
			text = yyget_text(state->scanner);
			TOKEN_SET(&val, string, cli_strdup(text));
			abort();
		}
		add_token(state, &val);
		current->last_token = yv;
		memset(&val, 0, sizeof(val));
		val.vtype = vtype_undefined;
	}
}
Пример #19
0
int check_stmt(is_stmt* node)
{
	int errors = 0;

	/* ; empty statement */
	if (!node)
		return 0;

	switch (node->type)
	{
		case t_stmt_stmt_list:
			node->data.stmt_list.scope = scope_new(NULL, false);
			scope_push(node->data.stmt_list.scope);
				errors += check_stmt_list(node->data.stmt_list.list);
			scope_pop();

			if (errors == 0)
				node->terminates = node->data.stmt_list.list->terminated;
		break;

		case t_stmt_var_stmt:
			errors += check_var_stmt(node->data.var, false);
		break;

		case t_stmt_assign:
			errors += check_assign_op(node->data.assign);
		break;

		case t_stmt_incr:
			errors += check_incr_op(node->data.incr);
		break;

		case t_stmt_if:
			errors += check_if(node->data.if_stmt);
			if (errors == 0)
				node->terminates = node->data.if_stmt->terminates;
		break;

		case t_stmt_loop:
			errors += check_loop_stmt(node->data.loop);
			if (errors == 0)
				node->terminates = node->data.loop->terminates;
		break;

		case t_stmt_func_call:
			errors += check_func_call(node->data.func_call);
		break;

		case t_stmt_switch:
			errors += check_switch(node->data.switch_stmt);

			if (errors == 0)
				node->terminates = node->data.switch_stmt->terminates;
		break;

		case t_stmt_break:
			errors += check_break(node->data.break_stmt);
			node->terminates = true;
		break;

		case t_stmt_continue:
			errors += check_continue(node->data.continue_stmt);
			node->terminates = true;
		break;
		
		case t_stmt_return:
			errors += check_return(node->data.return_stmt);
			node->terminates = true;
		break;
	}

	return errors;
}