// File: /workspace/github_c_makefile_star2_O1/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
testq %rdi, %rdi
je 0x2b8c0
movq %r8, -0x40(%rbp)
testq %rdx, %rdx
je 0x2b8df
movq %rsi, %r14
movq %rdi, %rbx
movq (%rsi), %rax
movq (%rax), %rax
movq (%rax), %rdi
leaq 0x1bf69(%rip), %rax     # 0x472c0
movq %rdx, %rsi
movl %ecx, %edx
movq %rax, %rcx
callq 0xae24
movq %rax, %r13
movq %r14, 0x2080(%rax)
movq %rax, %rdi
callq 0xb8d6
movq %r13, %rdi
callq 0xb36e
testq %rax, %rax
je 0x2b868
movq %rax, %r12
movq %r13, -0x38(%rbp)
movq %r14, -0x30(%rbp)
movq %rbx, -0x70(%rbp)
movl (%r12), %eax
cmpl $0x11, %eax
jg 0x2b3b6
cmpl $0x3, %eax
jb 0x2b43a
cmpl $0x10, %eax
je 0x2b43a
jmp 0x2b8a1
cmpl $0x20, %eax
jg 0x2b428
cmpl $0x12, %eax
je 0x2b465
cmpl $0x20, %eax
jne 0x2b8a1
movq 0x8(%r12), %rsi
movl 0x4(%r12), %edx
leaq -0xf8(%rbp), %r15
movq %r15, %rdi
callq 0xe60d
movq -0x40(%rbp), %r14
testq %r14, %r14
je 0x2b561
movq %r14, %rdi
movq %r15, %rsi
callq 0xc91a
testb %al, %al
je 0x2b561
movq %r14, %rdi
movq %r15, %rsi
callq 0xc7de
movq %rbx, %rdi
movq %rax, %rsi
callq 0xe7ac
movq %r15, %rdi
movq -0x30(%rbp), %r14
jmp 0x2b57d
cmpl $0x21, %eax
je 0x2b4ea
cmpl $0x22, %eax
jne 0x2b8a1
movq 0x8(%r12), %rsi
movl 0x4(%r12), %edx
movq %rbx, %rdi
callq 0xe688
movq %r13, %rdi
callq 0xb36e
movq %rax, %r12
testq %rax, %rax
jne 0x2b396
jmp 0x2b868
movq %r13, %rdi
callq 0xb36e
movq %rax, %r13
testq %rax, %rax
je 0x2b47c
cmpl $0x20, (%r13)
je 0x2b48c
movq (%r14), %rdi
movq %r12, %rsi
leaq 0xb8a4(%rip), %rdx      # 0x36d2d
callq *0x50(%rdi)
movq %r14, %r12
movq 0x8(%r13), %rsi
movl 0x4(%r13), %edx
leaq -0xf8(%rbp), %r15
movq %r15, %rdi
callq 0xe60d
movq %rbx, %rdi
movl $0x22, %esi
callq 0xe5eb
movq -0x40(%rbp), %r14
testq %r14, %r14
je 0x2b535
movq %r14, %rdi
movq %r15, %rsi
callq 0xc91a
testb %al, %al
je 0x2b535
movq %r14, %rdi
movq %r15, %rsi
callq 0xc7de
movq %rbx, %rdi
movq %rax, %rsi
callq 0xe7ac
movq -0x38(%rbp), %r13
movq %r12, %r14
jmp 0x2b54f
leaq -0xb0(%rbp), %r15
movq %r15, %rdi
callq 0xe468
leaq -0x68(%rbp), %r13
movq %r13, %rdi
callq 0xe468
cmpl $0x0, 0x4(%r12)
jle 0x2b587
xorl %ebx, %ebx
movq 0x8(%r12), %rax
movb (%rax,%rbx), %al
cmpb $0x28, %al
je 0x2b589
movsbl %al, %esi
movq %r15, %rdi
callq 0xe5eb
incq %rbx
movslq 0x4(%r12), %rax
cmpq %rax, %rbx
jl 0x2b50f
jmp 0x2b589
movq 0x8(%r13), %rdx
movl 0x4(%r13), %ecx
movq %rbx, %rdi
movq %r12, %r14
movq %r12, %rsi
callq 0x2b10b
movq -0x38(%rbp), %r13
movq %rbx, %rdi
movl $0x22, %esi
callq 0xe5eb
jmp 0x2b44c
movq 0x8(%r12), %rdx
movl 0x4(%r12), %ecx
movq %rbx, %rdi
movq -0x30(%rbp), %r14
movq %r14, %rsi
callq 0x2b10b
movq %r15, %rdi
callq 0xe958
jmp 0x2b44c
xorl %ebx, %ebx
cmpl 0x4(%r12), %ebx
jge 0x2b5ad
movl %ebx, %ebx
movq 0x8(%r12), %rax
movsbl (%rax,%rbx), %esi
movq %r13, %rdi
callq 0xe5eb
incq %rbx
cmpl %ebx, 0x4(%r12)
jg 0x2b592
movq 0x20(%r14), %rdi
movq %r15, %rsi
callq 0xc7de
movq %rax, -0x48(%rbp)
leaq -0xf8(%rbp), %rdi
leaq -0x1e873(%rip), %rdx    # 0xcd58
movq %rdx, %rsi
leaq -0x1cc35(%rip), %rbx    # 0xe9a0
movq %rbx, %rcx
movq %rbx, %r8
callq 0xc4ec
leaq -0xa0(%rbp), %rdi
xorl %esi, %esi
movq %rbx, %rdx
callq 0xbccc
callq 0xe84a
movq %rax, %r13
cmpl $0x2, -0x64(%rbp)
jl 0x2b6c6
movl $0x1, %r14d
movl $0x1, %ebx
leaq 0x41a1(%rip), %r15      # 0x2f7b6
movq -0x60(%rbp), %rax
testq %rax, %rax
cmoveq %r15, %rax
movb (%rax,%rbx), %al
movzbl %al, %ecx
cmpl $0x2b, %ecx
jg 0x2b644
cmpl $0x28, %ecx
je 0x2b693
cmpl $0x29, %ecx
jne 0x2b6ab
cmpl $0x2, %r14d
jl 0x2b819
decl %r14d
jmp 0x2b6ab
cmpl $0x2c, %ecx
jne 0x2b6a3
cmpl $0x2, %r14d
jge 0x2b6ab
cmpl $0x1, %r14d
jne 0x2b882
cmpl $0x0, 0x4(%r13)
jne 0x2b674
movq -0x30(%rbp), %rax
movq (%rax), %rdi
movq %r12, %rsi
leaq 0xbde9(%rip), %rdx      # 0x3745a
callq *0x50(%rdi)
leaq -0xa0(%rbp), %rdi
movq %r13, %rsi
callq 0xbddf
movl $0x1, %r14d
callq 0xe84a
movq %rax, %r13
jmp 0x2b6b6
movsbl %al, %esi
movq %r13, %rdi
callq 0xe5eb
incl %r14d
jmp 0x2b6b6
cmpl $0xff, %ecx
je 0x2b6c6
movsbl %al, %esi
movq %r13, %rdi
callq 0xe5eb
incq %rbx
movslq -0x64(%rbp), %rax
cmpq %rax, %rbx
jl 0x2b615
testq %r13, %r13
je 0x2b6d3
movq %r13, %rdi
callq 0xe9a0
movq -0x40(%rbp), %rbx
movq -0x48(%rbp), %rax
movq 0x10(%rax), %rax
cmpq -0x90(%rbp), %rax
je 0x2b6fc
movq -0x30(%rbp), %rax
movq (%rax), %rdi
movq %r12, %rsi
leaq 0xbd87(%rip), %rdx      # 0x37480
callq *0x50(%rdi)
movq -0x48(%rbp), %rax
movq (%rax), %r14
testq %r14, %r14
movq -0x30(%rbp), %r12
je 0x2b7a6
movq -0xa0(%rbp), %r15
movq 0x8(%r14), %rax
movq %rax, -0x78(%rbp)
movq %rbx, %r12
movq 0x8(%r15), %rbx
callq 0xe84a
movq %rax, %r13
leaq -0x58(%rbp), %rdi
callq 0xe468
leaq -0x58(%rbp), %rdi
movq %rbx, %rsi
movq %r12, %rbx
movq -0x30(%rbp), %r12
leaq -0x1c2ad(%rip), %rdx    # 0xf49f
callq 0xf6fa
movq -0x50(%rbp), %rdx
testq %rdx, %rdx
leaq 0x4057(%rip), %rax      # 0x2f7b6
cmoveq %rax, %rdx
movl -0x54(%rbp), %ecx
movq %r13, %rdi
movq %r12, %rsi
movq %rbx, %r8
callq 0x2b317
leaq -0x58(%rbp), %rdi
callq 0xe958
leaq -0xf8(%rbp), %rdi
movq -0x78(%rbp), %rsi
movq %r13, %rdx
movl $0x1, %ecx
callq 0xc658
movq 0x18(%r14), %r14
movq 0x18(%r15), %r15
testq %r14, %r14
jne 0x2b717
movq -0x48(%rbp), %rax
movq 0x30(%rax), %rdx
testq %rdx, %rdx
leaq 0x3ffe(%rip), %rcx      # 0x2f7b6
cmoveq %rcx, %rdx
movl 0x2c(%rax), %ecx
movq -0x70(%rbp), %rbx
movq %rbx, %rdi
movq %r12, %rsi
leaq -0xf8(%rbp), %r14
movq %r14, %r8
callq 0x2b317
leaq -0xa0(%rbp), %rdi
movl $0x1, %esi
callq 0xbd6d
movq %r14, %rdi
xorl %esi, %esi
movl $0x1, %edx
callq 0xc5ca
leaq -0xb0(%rbp), %rdi
callq 0xe958
leaq -0x68(%rbp), %rdi
callq 0xe958
movq %r12, %r14
movq -0x38(%rbp), %r13
jmp 0x2b44c
cmpl $0x1, %r14d
jne 0x2b8fe
cmpl $0x0, 0x4(%r13)
jle 0x2b841
leaq -0xa0(%rbp), %rdi
movq %r13, %rsi
callq 0xbddf
xorl %r13d, %r13d
jmp 0x2b6c6
cmpq $0x0, -0x90(%rbp)
je 0x2b6c6
movq -0x30(%rbp), %rax
movq (%rax), %rdi
movq %r12, %rsi
leaq 0xbbfa(%rip), %rdx      # 0x3745a
callq *0x50(%rdi)
jmp 0x2b6c6
movq %r13, %rdi
callq 0xb119
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x3b0b(%rip), %rdi      # 0x2f394
leaq 0xba4e(%rip), %rsi      # 0x372de
leaq 0xbb62(%rip), %rcx      # 0x373f9
movl $0x21d, %edx            # imm = 0x21D
callq 0xa0b0
leaq 0x3aec(%rip), %rdi      # 0x2f394
leaq 0xba2f(%rip), %rsi      # 0x372de
leaq 0xbb43(%rip), %rcx      # 0x373f9
movl $0x277, %edx            # imm = 0x277
callq 0xa0b0
leaq 0x4199(%rip), %rdi      # 0x2fa60
leaq 0xba10(%rip), %rsi      # 0x372de
leaq 0xbb24(%rip), %rcx      # 0x373f9
movl $0x19d, %edx            # imm = 0x19D
callq 0xa0b0
leaq 0x4617(%rip), %rdi      # 0x2fefd
leaq 0xb9f1(%rip), %rsi      # 0x372de
leaq 0xbb05(%rip), %rcx      # 0x373f9
movl $0x19f, %edx            # imm = 0x19F
callq 0xa0b0
leaq 0x3a8f(%rip), %rdi      # 0x2f394
leaq 0xb9d2(%rip), %rsi      # 0x372de
leaq 0xbae6(%rip), %rcx      # 0x373f9
movl $0x232, %edx            # imm = 0x232
callq 0xa0b0