// File: /workspace/github_c_makefile_star2_O2/Ihsoh[P]ilang/compiler/preprocessor/line.c
// Function: expand_with_params_rstr
static void _expand_with_params_rstr(
	ResizableString *rstr,
	PPGeneratorContext *genctx,
	const char *src,
	int len,
	Map *params
) {
	assert(rstr);
	assert(genctx);
	assert(src);

	// 创建一个Lexer用于解析普通行。
	// 这些普通行内包含一些宏调用，需要把它们识别出来，并在后续将它们展开。
	LexerContext *ctx = lexer_new_context(
		genctx->psrctx->lexctx->file,
		src,
		len,
		_matchers
	);

	// 需要把PPGeneratorContext的实例传递给Lexer。
	//
	// 其中一个作用是被用于LEXER_MATCHER(func_macro_call)中，用于判断一个标识符
	// 是否已经被定义为函数宏。
	ctx->data = genctx;

	lexer_parse_first(ctx);

	LexerToken *token;
	while ((token = lexer_next_token(ctx)) != NULL) {
		switch (token->type) {
			case _TOKEN_SPACE:
			case _TOKEN_LITERAL_CHAR:
			case _TOKEN_LITERAL_STRING:
			case _TOKEN_PNCT:
			case _TOKEN_TEXT: {
				// 如果为以下的任意一项，将直接原样疏忽：
				//		1、空白
				//		2、字符常量
				//		3、字符串常量
				//		4、普通标点符号
				//		5、普通文本（非##、#、函数宏调用、标识符）
				rstr_append_with_raw(rstr, token->content, token->len);

				break;
			}
			case _TOKEN_PNCT_POUND: {
				// 
				ResizableString rstr_id;
				LexerToken *tk_id = lexer_next_token(ctx);
				if (tk_id == NULL
						|| tk_id->type != _TOKEN_IDENTIFIER) {
					_SYNERR_TOKEN(genctx, token, "expect identifier.");
				}
				rstr_init_with_raw(&rstr_id, tk_id->content, tk_id->len);

				rstr_append_with_char(rstr, '\"');

				if (params != NULL
						&& map_exists_key(params, &rstr_id)) {
					ResizableString *rstr_val = map_get(params, &rstr_id);
					rstr_append_with_rstr(rstr, rstr_val);
				} else {
					_expand_macro_rstr(rstr, genctx, tk_id->content, tk_id->len);
				}
				
				rstr_append_with_char(rstr, '\"');
				break;
			}
			case _TOKEN_IDENTIFIER: {
				ResizableString rstr_id;
				rstr_init_with_raw(&rstr_id, token->content, token->len);

				if (params != NULL
						&& map_exists_key(params, &rstr_id)) {
					ResizableString *rstr_val = map_get(params, &rstr_id);
					rstr_append_with_rstr(rstr, rstr_val);
				} else {
					_expand_macro_rstr(rstr, genctx, token->content, token->len);
				}

				rstr_free(&rstr_id);
				break;
			}
			case _TOKEN_FUNC_MACRO_CALL: {
				ResizableString rstr_id;
				rstr_init(&rstr_id);

				ResizableString rstr_param_values;
				rstr_init(&rstr_param_values);

				int idx = 0;
				for (; idx < token->len; idx++) {
					if (token->content[idx] != '(') {
						rstr_append_with_char(&rstr_id, token->content[idx]);
					} else {
						break;
					}
				}

				for (; idx < token->len; idx++) {
					rstr_append_with_char(&rstr_param_values, token->content[idx]);
				}
			
				PPGeneratorFuncMacro *macro = map_get(genctx->map_kv_with_params, &rstr_id);

				Map map_params;
				map_init(
					&map_params,
					map_rstr_comparer, map_rstr_comparer,
					(MapReleaser) rstr_delete, (MapReleaser) rstr_delete
				);

				LinkedList llst_param_values;
				llst_init(
					&llst_param_values, NULL, (LinkedListReleaser) rstr_delete
				);
				
				
				int params_idx = 1;	// 跳过'('。
				#define	_GET_PARAMS_CHAR(i)	((i) >= RSTR_LEN(&rstr_param_values) ? -1 : RSTR_CHAR(&rstr_param_values, i))

				int paren_left_count = 1;
				ResizableString *rstr_param = rstr_new();
				while (_GET_PARAMS_CHAR(params_idx) != -1) {
					if (_GET_PARAMS_CHAR(params_idx) == ',') {
						if (paren_left_count > 1) {
							rstr_append_with_char(rstr_param, _GET_PARAMS_CHAR(params_idx));
						} else if (paren_left_count == 1) {
							if (RSTR_LEN(rstr_param) == 0) {
								_SYNERR_TOKEN(genctx, token, "macro call parameter cannot be empty.");
							}
							llst_append(&llst_param_values, rstr_param);
							rstr_param = rstr_new();
						} else {
							assert(0);
							break;
						}
					} else if (_GET_PARAMS_CHAR(params_idx) == '(') {
						rstr_append_with_char(rstr_param, _GET_PARAMS_CHAR(params_idx));
						++paren_left_count;
					} else if (_GET_PARAMS_CHAR(params_idx) == ')') {
						if (paren_left_count > 1) {
							--paren_left_count;
							rstr_append_with_char(rstr_param, _GET_PARAMS_CHAR(params_idx));
						} else if (paren_left_count == 1) {
							if (RSTR_LEN(rstr_param) > 0) {
								llst_append(&llst_param_values, rstr_param);
								rstr_param = NULL;
							} else {
								if (LLST_LEN(&llst_param_values) != 0) {
									_SYNERR_TOKEN(genctx, token, "macro call parameter cannot be empty.");
								}
							}
							break;
						} else {
							assert(0);
							break;
						}
					} else {
						rstr_append_with_char(rstr_param, _GET_PARAMS_CHAR(params_idx));
					}

					++params_idx;
				}
				if (rstr_param != NULL) {
					rstr_delete(rstr_param);
					rstr_param = NULL;
				}

				#undef	_GET_PARAMS_CHAR


				if (macro->params.count != llst_param_values.count) {
					_SYNERR_TOKEN(genctx, token, "function macro parameter count not matched.");
				}

				LinkedListNode *node_param_name = macro->params.head;
				LinkedListNode *node_param_value = llst_param_values.head;
				while (node_param_name != NULL) {
					ResizableString *rstr_param_name = (ResizableString *) node_param_name->data;
					ResizableString *rstr_param_value = (ResizableString *) node_param_value->data;

					ResizableString *rstr_expanded_param_value = rstr_new();

					ResizableString rstr_tmp;
					rstr_init(&rstr_tmp);
					rstr_trim_ex(&rstr_tmp, rstr_param_value, RSTR_SPACE_CHAR_COMPARER);

					_expand_with_params_rstr(
						rstr_expanded_param_value,
						genctx,
						RSTR_CSTR(&rstr_tmp),
						RSTR_LEN(&rstr_tmp),
						params
					);

					rstr_free(&rstr_tmp);

					map_set(
						&map_params,
						rstr_param_name,
						rstr_expanded_param_value,
						true
					);

					node_param_name = node_param_name->next;
					node_param_value = node_param_value->next;
				}

				_expand_with_params_rstr(
					rstr, genctx, RSTR_CSTR(&(macro->body)), RSTR_LEN(&(macro->body)), &map_params
				);

				llst_free(&llst_param_values, true);
				
				map_free(&map_params, false, true);

				rstr_free(&rstr_id);

				rstr_free(&rstr_param_values);

				break;
			}
			default: {
				assert(0);
			}
		}
	}

	lexer_free_context(ctx);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xd8, %rsp
movq %rsi, -0x30(%rbp)
testq %rdi, %rdi
je 0x29914
testq %rdx, %rdx
je 0x29933
movq %r8, %r15
movq %rdi, %r14
movq -0x30(%rbp), %rbx
movq (%rbx), %rax
movq (%rax), %rax
movq (%rax), %rdi
leaq 0x1be9f(%rip), %rax     # 0x452c0
movq %rdx, %rsi
movl %ecx, %edx
movq %rax, %rcx
callq 0xac5c
movq %rbx, 0x2080(%rax)
movq %rax, %rbx
movq %rax, %rdi
callq 0xb677
leaq -0xf8(%rbp), %r13
movq %r15, -0x40(%rbp)
movq %r14, -0x60(%rbp)
movq %rbx, -0x58(%rbp)
movq %rbx, %rdi
callq 0xb167
testq %rax, %rax
je 0x298bc
movq %rax, %r12
movl (%rax), %eax
cmpl $0x3, %eax
jb 0x29493
cmpl $0x22, %eax
je 0x29493
cmpl $0x12, %eax
je 0x29619
cmpl $0x20, %eax
je 0x2969d
cmpl $0x21, %eax
je 0x294a7
cmpl $0x10, %eax
jne 0x298f5
movq 0x8(%r12), %rsi
movl 0x4(%r12), %edx
movq %r14, %rdi
callq 0xe00f
jmp 0x29453
leaq -0x78(%rbp), %rdi
callq 0xde1c
leaq -0x50(%rbp), %rdi
callq 0xde1c
xorl %ebx, %ebx
movslq 0x4(%r12), %rax
cmpq %rax, %rbx
jge 0x294fd
movq 0x8(%r12), %rcx
movb (%rcx,%rbx), %cl
cmpb $0x28, %cl
je 0x294fd
movsbl %cl, %esi
leaq -0x78(%rbp), %rdi
callq 0xdf81
incq %rbx
jmp 0x294bb
movq 0x8(%r12), %rax
movsbl (%rax,%rbx), %esi
leaq -0x50(%rbp), %rdi
callq 0xdf81
incq %rbx
movl 0x4(%r12), %eax
cltq
cmpq %rax, %rbx
jl 0x294e3
movq -0x30(%rbp), %rax
movq 0x20(%rax), %rdi
leaq -0x78(%rbp), %rsi
callq 0xc417
movq %rax, -0x38(%rbp)
movq %r13, %rdi
leaq -0x1cbe4(%rip), %rdx    # 0xc93f
movq %rdx, %rsi
leaq -0x1b233(%rip), %rbx    # 0xe2fa
movq %rbx, %rcx
movq %rbx, %r8
callq 0xc13c
leaq -0xb0(%rbp), %rdi
xorl %esi, %esi
movq %rbx, %rdx
callq 0xba38
callq 0xe1d5
movq %rax, %r13
pushq $0x1
popq %rbx
pushq $0x1
popq %r14
movslq -0x4c(%rbp), %rax
cmpq %rax, %rbx
jge 0x296e6
movq -0x48(%rbp), %rax
testq %rax, %rax
leaq 0x421f(%rip), %rcx      # 0x2d792
cmoveq %rcx, %rax
movzbl (%rax,%rbx), %eax
cmpl $0x28, %eax
je 0x295b1
cmpl $0x29, %eax
je 0x2959d
cmpl $0x2c, %eax
je 0x295c1
cmpl $0xff, %eax
je 0x296e6
movsbl %al, %esi
movq %r13, %rdi
jmp 0x295cd
cmpl $0x2, %r14d
jl 0x2986c
decl %r14d
movq %r13, %rdi
pushq $0x29
jmp 0x295cc
movq %r13, %rdi
pushq $0x28
popq %rsi
callq 0xdf81
incl %r14d
jmp 0x295d2
cmpl $0x2, %r14d
jl 0x295d7
movq %r13, %rdi
pushq $0x2c
popq %rsi
callq 0xdf81
incq %rbx
jmp 0x29558
cmpl $0x1, %r14d
jne 0x298d6
cmpl $0x0, 0x4(%r13)
jne 0x295fc
movq -0x30(%rbp), %rax
movq (%rax), %rdi
movq %r12, %rsi
leaq 0xbe58(%rip), %rdx      # 0x35451
callq *0x50(%rdi)
leaq -0xb0(%rbp), %rdi
movq %r13, %rsi
callq 0xbb35
callq 0xe1d5
movq %rax, %r13
pushq $0x1
popq %r14
jmp 0x295d2
movq %rbx, %rdi
callq 0xb167
movq %rax, %r13
testq %rax, %rax
je 0x29630
cmpl $0x20, (%r13)
je 0x29644
movq -0x30(%rbp), %rax
movq (%rax), %rdi
movq %r12, %rsi
leaq 0xb724(%rip), %rdx      # 0x34d65
callq *0x50(%rdi)
movq 0x8(%r13), %rsi
movl 0x4(%r13), %edx
leaq -0xf8(%rbp), %r12
movq %r12, %rdi
callq 0xdfa2
movq %r14, %rdi
pushq $0x22
popq %rsi
callq 0xdf81
testq %r15, %r15
je 0x29822
movq %r15, %rdi
movq %r12, %rsi
callq 0xc52c
testb %al, %al
je 0x29822
movq %r15, %rdi
movq %r12, %rsi
callq 0xc417
movq %r14, %rdi
movq %rax, %rsi
callq 0xe12e
jmp 0x29836
movq 0x8(%r12), %rsi
movl 0x4(%r12), %edx
movq %r13, %rdi
callq 0xdfa2
testq %r15, %r15
je 0x29849
movq %r15, %rdi
movq %r13, %rsi
callq 0xc52c
testb %al, %al
je 0x29849
movq %r15, %rdi
movq %r13, %rsi
callq 0xc417
movq %r14, %rdi
movq %rax, %rsi
callq 0xe12e
jmp 0x2985f
testq %r13, %r13
movq -0x38(%rbp), %rbx
je 0x296f7
movq %r13, %rdi
callq 0xe2fa
movq 0x10(%rbx), %rax
cmpq -0xa0(%rbp), %rax
je 0x29718
movq -0x30(%rbp), %rax
movq (%rax), %rdi
movq %r12, %rsi
leaq 0xbd62(%rip), %rdx      # 0x35477
callq *0x50(%rdi)
movq (%rbx), %r14
movq -0xb0(%rbp), %r15
testq %r14, %r14
je 0x297b3
movq 0x8(%r14), %rax
movq %rax, -0x68(%rbp)
movq 0x8(%r15), %rbx
callq 0xe1d5
movq %rax, %r13
leaq -0x88(%rbp), %r12
movq %r12, %rdi
callq 0xde1c
movq %r12, %rdi
movq %rbx, %rsi
leaq -0x1a9c0(%rip), %rdx    # 0xed9b
callq 0xefe8
movq -0x80(%rbp), %rdx
testq %rdx, %rdx
leaq 0x4024(%rip), %rax      # 0x2d792
cmoveq %rax, %rdx
movl -0x84(%rbp), %ecx
movq %r13, %rdi
movq -0x30(%rbp), %rsi
movq -0x40(%rbp), %r8
callq 0x293dd
movq %r12, %rdi
callq 0xe2b9
leaq -0xf8(%rbp), %rdi
movq -0x68(%rbp), %rsi
movq %r13, %rdx
pushq $0x1
popq %rcx
callq 0xc29d
movq 0x18(%r14), %r14
movq 0x18(%r15), %r15
jmp 0x29722
movq -0x38(%rbp), %rcx
movq 0x30(%rcx), %rdx
testq %rdx, %rdx
leaq 0x3fcd(%rip), %rax      # 0x2d792
cmoveq %rax, %rdx
movl 0x2c(%rcx), %ecx
movq -0x60(%rbp), %r14
movq %r14, %rdi
movq -0x30(%rbp), %rsi
leaq -0xf8(%rbp), %r13
movq %r13, %r8
callq 0x293dd
leaq -0xb0(%rbp), %rdi
pushq $0x1
popq %rbx
movl %ebx, %esi
callq 0xbad0
movq %r13, %rdi
xorl %esi, %esi
movl %ebx, %edx
callq 0xc214
leaq -0x78(%rbp), %rdi
callq 0xe2b9
leaq -0x50(%rbp), %rdi
callq 0xe2b9
movq -0x40(%rbp), %r15
movq -0x58(%rbp), %rbx
jmp 0x29453
movq 0x8(%r13), %rdx
movl 0x4(%r13), %ecx
movq %r14, %rdi
movq -0x30(%rbp), %rsi
callq 0x291d3
movq %r12, %r13
movq %r14, %rdi
pushq $0x22
popq %rsi
callq 0xdf81
jmp 0x29453
movq 0x8(%r12), %rdx
movl 0x4(%r12), %ecx
movq %r14, %rdi
movq -0x30(%rbp), %rsi
callq 0x291d3
movq %r13, %rdi
callq 0xe2b9
jmp 0x29453
cmpl $0x1, %r14d
jne 0x29952
cmpl $0x0, 0x4(%r13)
movq -0x38(%rbp), %rbx
jle 0x29895
leaq -0xb0(%rbp), %rdi
movq %r13, %rsi
callq 0xbb35
jmp 0x296f7
cmpq $0x0, -0xa0(%rbp)
je 0x296ef
movq -0x30(%rbp), %rax
movq (%rax), %rdi
movq %r12, %rsi
leaq 0xbb9d(%rip), %rdx      # 0x35451
callq *0x50(%rdi)
jmp 0x296ef
movq %rbx, %rdi
callq 0xaf21
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x3a93(%rip), %rdi      # 0x2d370
leaq 0xb9f1(%rip), %rsi      # 0x352d5
leaq 0xbb05(%rip), %rcx      # 0x353f0
movl $0x21d, %edx            # imm = 0x21D
callq 0xa0b0
leaq 0x3a74(%rip), %rdi      # 0x2d370
leaq 0xb9d2(%rip), %rsi      # 0x352d5
leaq 0xbae6(%rip), %rcx      # 0x353f0
movl $0x277, %edx            # imm = 0x277
callq 0xa0b0
leaq 0x4125(%rip), %rdi      # 0x2da40
leaq 0xb9b3(%rip), %rsi      # 0x352d5
leaq 0xbac7(%rip), %rcx      # 0x353f0
movl $0x19d, %edx            # imm = 0x19D
callq 0xa0b0
leaq 0x45a3(%rip), %rdi      # 0x2dedd
leaq 0xb994(%rip), %rsi      # 0x352d5
leaq 0xbaa8(%rip), %rcx      # 0x353f0
movl $0x19f, %edx            # imm = 0x19F
callq 0xa0b0
leaq 0x3a17(%rip), %rdi      # 0x2d370
leaq 0xb975(%rip), %rsi      # 0x352d5
leaq 0xba89(%rip), %rcx      # 0x353f0
movl $0x232, %edx            # imm = 0x232
callq 0xa0b0