<commit_before>#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#include "../util/util.h"
#include "data_structs.h"
#include "tokenise.h"
#include "parse.h"
#include "../util/alloc.h"
#include "tokconv.h"
#include "../util/util.h"
#include "sym.h"
#include "cc1.h"
#include "../util/dynarray.h"
#include "sue.h"
#include "parse_type.h"
#include "const.h"
#include "ops/__builtin.h"
#include "funcargs.h"

#define STAT_NEW(type)      stmt_new_wrapper(type, current_scope)
#define STAT_NEW_NEST(type) stmt_new_wrapper(type, symtab_new(current_scope))

stmt *parse_stmt_block(void);
stmt *parse_stmt(void);
expr **parse_funcargs(void);

expr *parse_expr_unary(void);
#define parse_expr_cast() parse_expr_unary()

/* parse_type uses this for structs, tdefs and enums */
symtable *current_scope;
static_assert **static_asserts;


/* sometimes we can carry on after an error, but we don't want to go through to compilation etc */
int parse_had_error = 0;


/* switch, for, do and while linkage */
static stmt *current_continue_target,
						*current_break_target,
						*current_switch;


expr *parse_expr_sizeof_typeof(int is_typeof)
{
	expr *e;

	if(accept(token_open_paren)){
		type_ref *r = parse_type();

		if(r){
			EAT(token_close_paren);

			/* check for sizeof(int){...} */
			if(curtok == token_open_block)
				e = expr_new_sizeof_expr(
							expr_new_compound_lit(r,
								parse_initialisation()),
							is_typeof);
			else
				e = expr_new_sizeof_type(r, is_typeof);

		}else{
			/* parse a full one, since we're in brackets */
			e = expr_new_sizeof_expr(parse_expr_exp(), is_typeof);
			EAT(token_close_paren);
		}

	}else{
		if(is_typeof)
			/* TODO? cc1_error = 1, return expr_new_val(0) */
			DIE_AT(NULL, "open paren expected after typeof");

		e = expr_new_sizeof_expr(parse_expr_unary(), is_typeof);
		/* don't go any higher, sizeof a - 1, means sizeof(a) - 1 */
	}

	return e;
}

expr *parse_expr__Generic()
{
	struct generic_lbl **lbls;
	expr *test;

	EAT(token__Generic);
	EAT(token_open_paren);

	test = parse_expr_no_comma();
	lbls = NULL;

	for(;;){
		type_ref *r;
		expr *e;
		struct generic_lbl *lbl;

		EAT(token_comma);

		if(accept(token_default)){
			r = NULL;
		}else{
			r = parse_type();
			if(!r)
				DIE_AT(NULL, "type expected");
		}
		EAT(token_colon);
		e = parse_expr_no_comma();

		lbl = umalloc(sizeof *lbl);
		lbl->e = e;
		lbl->t = r;
		dynarray_add(&lbls, lbl);

		if(accept(token_close_paren))
			break;
	}

	return expr_new__Generic(test, lbls);
}

expr *parse_expr_identifier()
{
	expr *e;

	if(curtok != token_identifier)
		DIE_AT(NULL, "identifier expected, got %s (%s:%d)",
				token_to_str(curtok), __FILE__, __LINE__);

	e = expr_new_identifier(token_current_spel());
	EAT(token_identifier);
	return e;
}

expr *parse_block()
{
	funcargs *args;
	type_ref *rt;

	EAT(token_xor);

	rt = parse_type();

	if(rt){
		if(type_ref_is(rt, type_ref_func)){
			/* got ^int (args...) */
			rt = type_ref_func_call(rt, &args);
		}else{
			/* ^int {...} */
			goto def_args;
		}

	}else if(accept(token_open_paren)){
		/* ^(args...) */
		args = parse_func_arglist();
		EAT(token_close_paren);
	}else{
		/* ^{...} */
def_args:
		args = funcargs_new();
		args->args_void = 1;
	}

	return expr_new_block(rt, args, parse_stmt_block());
}

expr *parse_expr_primary()
{
	switch(curtok){
		case token_integer:
		case token_character:
		{
			expr *e = expr_new_intval(&currentval);
			EAT(curtok);
			return e;
		}

		case token_string:
		/*case token_open_block: - not allowed here */
		{
			char *s;
			int l, wide;

			token_get_current_str(&s, &l, &wide);
			EAT(token_string);

			return expr_new_str(s, l, wide);
		}

		case token__Generic:
			return parse_expr__Generic();

		case token_xor:
			return parse_block();

		default:
			if(accept(token_open_paren)){
				type_ref *r;
				expr *e;

				if((r = parse_type())){
					e = expr_new_cast(r, 0);
					EAT(token_close_paren);

					if(curtok == token_open_block){
						/* C99 compound lit. */
						decl_init *init = parse_initialisation();

						expr_compound_lit_from_cast(e, init);

					}else{
						e->expr = parse_expr_cast(); /* another cast */
					}
					return e;

				}else if(curtok == token_open_block){
					/* ({ ... }) */
					e = expr_new_stmt(parse_stmt_block());
				}else{
					/* mark as being inside parens, for if((x = 5)) checking */
					e = parse_expr_exp();
					e->in_parens = 1;
				}

				EAT(token_close_paren);
				return e;
			}else{
				/* inline asm */
				if(accept(token_asm)){
					ICW("token_asm - redirect to builtin instead of identifier");
					return expr_new_identifier(ustrdup(ASM_INLINE_FNAME));
				}

				if(curtok != token_identifier){
					/* TODO? cc1_error = 1, return expr_new_val(0) */
					DIE_AT(NULL, "expression expected, got %s (%s:%d)",
							token_to_str(curtok), __FILE__, __LINE__);
				}

				return parse_expr_identifier();
			}
			break;
	}
}

expr *parse_expr_postfix()
{
	expr *e;
	int flag;

	e = parse_expr_primary();

	for(;;){
		if(accept(token_open_square)){
			expr *sum;

			sum = expr_new_op(op_plus);

			sum->lhs  = e;
			sum->rhs  = parse_expr_exp();

			EAT(token_close_square);

			e = expr_new_deref(sum);

		}else if(accept(token_open_paren)){
			expr *fcall = NULL;

			/* check for specialised builtin parsing */
			if(expr_kind(e, identifier))
				fcall = builtin_parse(e->bits.ident.spel);

			if(!fcall){
				fcall = expr_new_funcall();
				fcall->funcargs = parse_funcargs();
			}

			fcall->expr = e;
			EAT(token_close_paren);

			e = fcall;

		}else if((flag = accept(token_dot)) || accept(token_ptr)){
			e = expr_new_struct(e, flag, parse_expr_identifier());

		}else if((flag = accept(token_increment)) || accept(token_decrement)){
			e = expr_new_assign_compound(e, expr_new_val(1), flag ? op_plus : op_minus);
			e->assign_is_post = 1;

		}else{
			break;
		}
	}

	return e;
}

expr *parse_expr_unary()
{
	expr *e;
	int flag;

	if((flag = accept(token_increment)) || accept(token_decrement)){
		/* this is a normal increment, i.e. ++x, simply translate it to x += 1 */

		e = expr_new_assign_compound(
				parse_expr_unary(), /* lval */
				expr_new_val(1),
				flag ? op_plus : op_minus);

	}else{
		switch(curtok){
			case token_andsc:
				/* GNU &&label */
				EAT(curtok);
				e = expr_new_addr_lbl(token_current_spel());
				EAT(token_identifier);
				break;

			case token_and:
				EAT(token_and);
				e = expr_new_addr(parse_expr_cast());
				break;

			case token_multiply:
				EAT(curtok);
				e = expr_new_deref(parse_expr_cast());
				break;

			case token_plus:
			case token_minus:
			case token_bnot:
			case token_not:
				e = expr_new_op(curtok_to_op());
				EAT(curtok);
				e->lhs = parse_expr_cast();
				break;

			case token_sizeof:
				EAT(token_sizeof);
				e = parse_expr_sizeof_typeof(0);
				break;

			default:
				e = parse_expr_postfix();
		}
	}

	return e;
}

expr *parse_expr_generic(expr *(*above)(), enum token t, ...)
{
	expr *e = above();

	for(;;){
		expr *join;
		int have = curtok == t;

		if(!have){
			va_list l; va_start(l, t);
			have = curtok_in_list(l);
			va_end(l);
		}

		if(!have)
			break;

		join = expr_new_op(curtok_to_op());
		EAT(curtok);
		join->lhs = e;
		join->rhs = above();
		e = join;
	}

	return e;
}

#define PARSE_DEFINE(this, above, ...) \
expr *parse_expr_ ## this()            \
{                                      \
	return parse_expr_generic(           \
			parse_expr_ ## above,            \
			__VA_ARGS__, token_unknown);     \
}

/* cast is handled in unary instead */
PARSE_DEFINE(multi,     /*cast,*/unary,  token_multiply, token_divide, token_modulus)
PARSE_DEFINE(additive,    multi,         token_plus, token_minus)
PARSE_DEFINE(shift,       additive,      token_shiftl, token_shiftr)
PARSE_DEFINE(relational,  shift,         token_lt, token_gt, token_le, token_ge)
PARSE_DEFINE(equality,    relational,    token_eq, token_ne)
PARSE_DEFINE(binary_and,  equality,      token_and)
PARSE_DEFINE(binary_xor,  binary_and,    token_xor)
PARSE_DEFINE(binary_or,   binary_xor,    token_or)
PARSE_DEFINE(logical_and, binary_or,     token_andsc)
PARSE_DEFINE(logical_or,  logical_and,   token_orsc)

expr *parse_expr_conditional()
{
	expr *e = parse_expr_logical_or();

	if(accept(token_question)){
		expr *q = expr_new_if(e);

		if(accept(token_colon)){
			q->lhs = NULL; /* sentinel */
		}else{
			q->lhs = parse_expr_exp();
			EAT(token_colon);
		}
		q->rhs = parse_expr_conditional();

		return q;
	}
	return e;
}

expr *parse_expr_assignment()
{
	expr *e;

	e = parse_expr_conditional();

	if(accept(token_assign)){
		return expr_new_assign(e, parse_expr_assignment());

	}else if(curtok_is_compound_assignment()){
		/* +=, ... - only evaluate the lhs once*/
		enum op_type op = curtok_to_compound_op();

		EAT(curtok);

		return expr_new_assign_compound(e, parse_expr_assignment(), op);
	}

	return e;
}

expr *parse_expr_exp()
{
	expr *e;

	e = parse_expr_assignment();

	if(accept(token_comma)){
		expr *ret = expr_new_comma();
		ret->lhs = e;
		ret->rhs = parse_expr_exp();
		return ret;
	}
	return e;
}

type_ref **parse_type_list()
{
	type_ref **types = NULL;

	if(curtok == token_close_paren)
		return types;

	do{
		type_ref *r = parse_type();

		if(!r)
			DIE_AT(NULL, "type expected");

		dynarray_add(&types, r);
	}while(accept(token_comma));

	return types;
}

expr **parse_funcargs()
{
	expr **args = NULL;

	while(curtok != token_close_paren){
		expr *arg = parse_expr_no_comma();
		if(!arg)
			DIE_AT(&arg->where, "expected: funcall arg");
		dynarray_add(&args, arg);

		if(curtok == token_close_paren)
			break;
		EAT(token_comma);
	}

	return args;
}

void parse_test_init_expr(stmt *t)
{
	decl *d;

	EAT(token_open_paren);

	d = parse_decl_single(DECL_SPEL_NEED);
	if(d){
		t->flow = stmt_flow_new(symtab_new(t->symtab));

		current_scope = t->flow->for_init_symtab;

		dynarray_add(&t->flow->for_init_decls, d);
<commit_msg>static where possible in parse.c<commit_after>#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#include "../util/util.h"
#include "data_structs.h"
#include "tokenise.h"
#include "parse.h"
#include "../util/alloc.h"
#include "tokconv.h"
#include "../util/util.h"
#include "sym.h"
#include "cc1.h"
#include "../util/dynarray.h"
#include "sue.h"
#include "parse_type.h"
#include "const.h"
#include "ops/__builtin.h"
#include "funcargs.h"

#define STAT_NEW(type)      stmt_new_wrapper(type, current_scope)
#define STAT_NEW_NEST(type) stmt_new_wrapper(type, symtab_new(current_scope))

stmt *parse_stmt_block(void);
stmt *parse_stmt(void);
expr **parse_funcargs(void);

expr *parse_expr_unary(void);
#define parse_expr_cast() parse_expr_unary()

/* parse_type uses this for structs, tdefs and enums */
symtable *current_scope;
static static_assert **static_asserts;


/* sometimes we can carry on after an error, but we don't want to go through to compilation etc */
int parse_had_error = 0;


/* switch, for, do and while linkage */
static stmt *current_continue_target,
						*current_break_target,
						*current_switch;


expr *parse_expr_sizeof_typeof(int is_typeof)
{
	expr *e;

	if(accept(token_open_paren)){
		type_ref *r = parse_type();

		if(r){
			EAT(token_close_paren);

			/* check for sizeof(int){...} */
			if(curtok == token_open_block)
				e = expr_new_sizeof_expr(
							expr_new_compound_lit(r,
								parse_initialisation()),
							is_typeof);
			else
				e = expr_new_sizeof_type(r, is_typeof);

		}else{
			/* parse a full one, since we're in brackets */
			e = expr_new_sizeof_expr(parse_expr_exp(), is_typeof);
			EAT(token_close_paren);
		}

	}else{
		if(is_typeof)
			/* TODO? cc1_error = 1, return expr_new_val(0) */
			DIE_AT(NULL, "open paren expected after typeof");

		e = expr_new_sizeof_expr(parse_expr_unary(), is_typeof);
		/* don't go any higher, sizeof a - 1, means sizeof(a) - 1 */
	}

	return e;
}

expr *parse_expr__Generic()
{
	struct generic_lbl **lbls;
	expr *test;

	EAT(token__Generic);
	EAT(token_open_paren);

	test = parse_expr_no_comma();
	lbls = NULL;

	for(;;){
		type_ref *r;
		expr *e;
		struct generic_lbl *lbl;

		EAT(token_comma);

		if(accept(token_default)){
			r = NULL;
		}else{
			r = parse_type();
			if(!r)
				DIE_AT(NULL, "type expected");
		}
		EAT(token_colon);
		e = parse_expr_no_comma();

		lbl = umalloc(sizeof *lbl);
		lbl->e = e;
		lbl->t = r;
		dynarray_add(&lbls, lbl);

		if(accept(token_close_paren))
			break;
	}

	return expr_new__Generic(test, lbls);
}

expr *parse_expr_identifier()
{
	expr *e;

	if(curtok != token_identifier)
		DIE_AT(NULL, "identifier expected, got %s (%s:%d)",
				token_to_str(curtok), __FILE__, __LINE__);

	e = expr_new_identifier(token_current_spel());
	EAT(token_identifier);
	return e;
}

expr *parse_block()
{
	funcargs *args;
	type_ref *rt;

	EAT(token_xor);

	rt = parse_type();

	if(rt){
		if(type_ref_is(rt, type_ref_func)){
			/* got ^int (args...) */
			rt = type_ref_func_call(rt, &args);
		}else{
			/* ^int {...} */
			goto def_args;
		}

	}else if(accept(token_open_paren)){
		/* ^(args...) */
		args = parse_func_arglist();
		EAT(token_close_paren);
	}else{
		/* ^{...} */
def_args:
		args = funcargs_new();
		args->args_void = 1;
	}

	return expr_new_block(rt, args, parse_stmt_block());
}

expr *parse_expr_primary()
{
	switch(curtok){
		case token_integer:
		case token_character:
		{
			expr *e = expr_new_intval(&currentval);
			EAT(curtok);
			return e;
		}

		case token_string:
		/*case token_open_block: - not allowed here */
		{
			char *s;
			int l, wide;

			token_get_current_str(&s, &l, &wide);
			EAT(token_string);

			return expr_new_str(s, l, wide);
		}

		case token__Generic:
			return parse_expr__Generic();

		case token_xor:
			return parse_block();

		default:
			if(accept(token_open_paren)){
				type_ref *r;
				expr *e;

				if((r = parse_type())){
					e = expr_new_cast(r, 0);
					EAT(token_close_paren);

					if(curtok == token_open_block){
						/* C99 compound lit. */
						decl_init *init = parse_initialisation();

						expr_compound_lit_from_cast(e, init);

					}else{
						e->expr = parse_expr_cast(); /* another cast */
					}
					return e;

				}else if(curtok == token_open_block){
					/* ({ ... }) */
					e = expr_new_stmt(parse_stmt_block());
				}else{
					/* mark as being inside parens, for if((x = 5)) checking */
					e = parse_expr_exp();
					e->in_parens = 1;
				}

				EAT(token_close_paren);
				return e;
			}else{
				/* inline asm */
				if(accept(token_asm)){
					ICW("token_asm - redirect to builtin instead of identifier");
					return expr_new_identifier(ustrdup(ASM_INLINE_FNAME));
				}

				if(curtok != token_identifier){
					/* TODO? cc1_error = 1, return expr_new_val(0) */
					DIE_AT(NULL, "expression expected, got %s (%s:%d)",
							token_to_str(curtok), __FILE__, __LINE__);
				}

				return parse_expr_identifier();
			}
			break;
	}
}

expr *parse_expr_postfix()
{
	expr *e;
	int flag;

	e = parse_expr_primary();

	for(;;){
		if(accept(token_open_square)){
			expr *sum;

			sum = expr_new_op(op_plus);

			sum->lhs  = e;
			sum->rhs  = parse_expr_exp();

			EAT(token_close_square);

			e = expr_new_deref(sum);

		}else if(accept(token_open_paren)){
			expr *fcall = NULL;

			/* check for specialised builtin parsing */
			if(expr_kind(e, identifier))
				fcall = builtin_parse(e->bits.ident.spel);

			if(!fcall){
				fcall = expr_new_funcall();
				fcall->funcargs = parse_funcargs();
			}

			fcall->expr = e;
			EAT(token_close_paren);

			e = fcall;

		}else if((flag = accept(token_dot)) || accept(token_ptr)){
			e = expr_new_struct(e, flag, parse_expr_identifier());

		}else if((flag = accept(token_increment)) || accept(token_decrement)){
			e = expr_new_assign_compound(e, expr_new_val(1), flag ? op_plus : op_minus);
			e->assign_is_post = 1;

		}else{
			break;
		}
	}

	return e;
}

expr *parse_expr_unary()
{
	expr *e;
	int flag;

	if((flag = accept(token_increment)) || accept(token_decrement)){
		/* this is a normal increment, i.e. ++x, simply translate it to x += 1 */

		e = expr_new_assign_compound(
				parse_expr_unary(), /* lval */
				expr_new_val(1),
				flag ? op_plus : op_minus);

	}else{
		switch(curtok){
			case token_andsc:
				/* GNU &&label */
				EAT(curtok);
				e = expr_new_addr_lbl(token_current_spel());
				EAT(token_identifier);
				break;

			case token_and:
				EAT(token_and);
				e = expr_new_addr(parse_expr_cast());
				break;

			case token_multiply:
				EAT(curtok);
				e = expr_new_deref(parse_expr_cast());
				break;

			case token_plus:
			case token_minus:
			case token_bnot:
			case token_not:
				e = expr_new_op(curtok_to_op());
				EAT(curtok);
				e->lhs = parse_expr_cast();
				break;

			case token_sizeof:
				EAT(token_sizeof);
				e = parse_expr_sizeof_typeof(0);
				break;

			default:
				e = parse_expr_postfix();
		}
	}

	return e;
}

expr *parse_expr_generic(expr *(*above)(), enum token t, ...)
{
	expr *e = above();

	for(;;){
		expr *join;
		int have = curtok == t;

		if(!have){
			va_list l; va_start(l, t);
			have = curtok_in_list(l);
			va_end(l);
		}

		if(!have)
			break;

		join = expr_new_op(curtok_to_op());
		EAT(curtok);
		join->lhs = e;
		join->rhs = above();
		e = join;
	}

	return e;
}

#define PARSE_DEFINE(this, above, ...) \
expr *parse_expr_ ## this()            \
{                                      \
	return parse_expr_generic(           \
			parse_expr_ ## above,            \
			__VA_ARGS__, token_unknown);     \
}

/* cast is handled in unary instead */
PARSE_DEFINE(multi,     /*cast,*/unary,  token_multiply, token_divide, token_modulus)
PARSE_DEFINE(additive,    multi,         token_plus, token_minus)
PARSE_DEFINE(shift,       additive,      token_shiftl, token_shiftr)
PARSE_DEFINE(relational,  shift,         token_lt, token_gt, token_le, token_ge)
PARSE_DEFINE(equality,    relational,    token_eq, token_ne)
PARSE_DEFINE(binary_and,  equality,      token_and)
PARSE_DEFINE(binary_xor,  binary_and,    token_xor)
PARSE_DEFINE(binary_or,   binary_xor,    token_or)
PARSE_DEFINE(logical_and, binary_or,     token_andsc)
PARSE_DEFINE(logical_or,  logical_and,   token_orsc)

expr *parse_expr_conditional()
{
	expr *e = parse_expr_logical_or();

	if(accept(token_question)){
		expr *q = expr_new_if(e);

		if(accept(token_colon)){
			q->lhs = NULL; /* sentinel */
		}else{
			q->lhs = parse_expr_exp();
			EAT(token_colon);
		}
		q->rhs = parse_expr_conditional();

		return q;
	}
	return e;
}

expr *parse_expr_assignment()
{
	expr *e;

	e = parse_expr_conditional();

	if(accept(token_assign)){
		return expr_new_assign(e, parse_expr_assignment());

	}else if(curtok_is_compound_assignment()){
		/* +=, ... - only evaluate the lhs once*/
		enum op_type op = curtok_to_compound_op();

		EAT(curtok);

		return expr_new_assign_compound(e, parse_expr_assignment(), op);
	}

	return e;
}

expr *parse_expr_exp()
{
	expr *e;

	e = parse_expr_assignment();

	if(accept(token_comma)){
		expr *ret = expr_new_comma();
		ret->lhs = e;
		ret->rhs = parse_expr_exp();
		return ret;
	}
	return e;
}

type_ref **parse_type_list()
{
	type_ref **types = NULL;

	if(curtok == token_close_paren)
		return types;

	do{
		type_ref *r = parse_type();

		if(!r)
			DIE_AT(NULL, "type expected");

		dynarray_add(&types, r);
	}while(accept(token_comma));

	return types;
}

expr **parse_funcargs()
{
	expr **args = NULL;

	while(curtok != token_close_paren){
		expr *arg = parse_expr_no_comma();
		if(!arg)
			DIE_AT(&arg->where, "expected: funcall arg");
		dynarray_add(&args, arg);

		if(curtok == token_close_paren)
			break;
		EAT(token_comma);
	}

	return args;
}

static void parse_test_init_expr(stmt *t)
{
	decl *d;

	EAT(token_open_paren);

	d = parse_decl_single(DECL_SPEL_NEED);
	if(d){
		t->flow = stmt_flow_new(symtab_new(t->symtab));

		current_scope = t->flow->for_init_symtab;

		dynarray_add(&t->flow->for_init_decls, d);

{'fraction_non_alphanumeric': 0.14638678250389192, 'fraction_numerical': 0.0021091749108622508, 'mean_word_length': 3.5548947849954255, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '298115', 'n_tokens_mistral': 8909, 'n_tokens_neox': 7756, 'n_words': 1540}