// File: /workspace/github_c_makefile_star2_O3/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 0x2aee8
movq %r8, -0x30(%rbp)
testq %rdx, %rdx
je 0x2af07
movq %rsi, %r14
movq %rdi, %rbx
movq (%rsi), %rax
movq (%rax), %rax
movq (%rax), %rdi
leaq 0x1b94d(%rip), %rax     # 0x462c0
movq %rdx, %rsi
movl %ecx, %edx
movq %rax, %rcx
callq 0xae18
movq %rax, %r15
movq %r14, 0x2080(%rax)
movq %rax, %rdi
callq 0xb8f0
movq %r15, %rdi
callq 0xb36c
testq %rax, %rax
je 0x2ae90
movq %rax, %r12
leaq -0xf8(%rbp), %r13
movq %rbx, -0x70(%rbp)
movq %r15, -0x68(%rbp)
movq %r14, -0x40(%rbp)
movl (%r12), %eax
cmpl $0x11, %eax
jg 0x2a9d1
cmpl $0x3, %eax
jb 0x2aa45
cmpl $0x10, %eax
je 0x2aa45
jmp 0x2aec9
cmpl $0x20, %eax
jg 0x2aa33
cmpl $0x12, %eax
je 0x2aa70
cmpl $0x20, %eax
jne 0x2aec9
movq 0x8(%r12), %rsi
movl 0x4(%r12), %edx
movq %r13, %rdi
callq 0xe41c
movq -0x30(%rbp), %rdi
testq %rdi, %rdi
je 0x2ae1f
movq %r13, %rsi
callq 0xc82a
testb %al, %al
movq -0x30(%rbp), %rdi
je 0x2ae1f
movq %r13, %rsi
callq 0xc6f2
movq %rbx, %rdi
movq %rax, %rsi
callq 0xe5be
jmp 0x2ae34
cmpl $0x21, %eax
je 0x2aaf4
cmpl $0x22, %eax
jne 0x2aec9
movq 0x8(%r12), %rsi
movl 0x4(%r12), %edx
movq %rbx, %rdi
callq 0xe497
movq %r15, %rdi
callq 0xb36c
movq %rax, %r12
testq %rax, %rax
jne 0x2a9b9
jmp 0x2ae90
movq %r15, %rdi
callq 0xb36c
movq %rax, %r13
testq %rax, %rax
je 0x2aa87
cmpl $0x20, (%r13)
je 0x2aa97
movq (%r14), %rdi
movq %r12, %rsi
leaq 0xb241(%rip), %rdx      # 0x35cd5
callq *0x50(%rdi)
movq 0x8(%r13), %rsi
movl 0x4(%r13), %edx
leaq -0xf8(%rbp), %r12
movq %r12, %rdi
callq 0xe41c
movq %rbx, %rdi
movl $0x22, %esi
callq 0xe3fa
movq -0x30(%rbp), %rdi
testq %rdi, %rdi
je 0x2adf7
movq %r12, %rsi
callq 0xc82a
testb %al, %al
movq -0x30(%rbp), %rdi
je 0x2adf7
movq %r12, %rsi
callq 0xc6f2
movq %rbx, %rdi
movq %rax, %rsi
callq 0xe5be
jmp 0x2ae0a
leaq -0x88(%rbp), %rdi
callq 0xe274
leaq -0x50(%rbp), %rdi
callq 0xe274
movl 0x4(%r12), %eax
xorl %ebx, %ebx
testl %eax, %eax
jle 0x2ab52
movq 0x8(%r12), %rcx
movb (%rcx), %cl
cmpb $0x28, %cl
je 0x2ab52
movl $0x1, %edx
movq %rdx, %rbx
movsbl %cl, %esi
leaq -0x88(%rbp), %rdi
callq 0xe3fa
movslq 0x4(%r12), %rax
cmpq %rax, %rbx
jge 0x2ab52
movq 0x8(%r12), %rcx
movb (%rcx,%rbx), %cl
leaq 0x1(%rbx), %rdx
cmpb $0x28, %cl
jne 0x2ab25
cmpl %eax, %ebx
leaq -0x50(%rbp), %r15
jge 0x2ab77
movl %ebx, %ebx
movq 0x8(%r12), %rax
movsbl (%rax,%rbx), %esi
movq %r15, %rdi
callq 0xe3fa
incq %rbx
cmpl %ebx, 0x4(%r12)
jg 0x2ab5c
movq %r14, %r15
movq 0x20(%r14), %rdi
leaq -0x88(%rbp), %rsi
callq 0xc6f2
movq %rax, -0x38(%rbp)
movq %r13, %rdi
leaq -0x1df30(%rip), %rdx    # 0xcc68
movq %rdx, %rsi
leaq -0x1c3e8(%rip), %rbx    # 0xe7ba
movq %rbx, %rcx
movq %rbx, %r8
callq 0xc400
leaq -0xb0(%rbp), %rdi
xorl %esi, %esi
movq %rbx, %rdx
callq 0xbc84
callq 0xe665
movq %rax, %r13
cmpl $0x2, -0x4c(%rbp)
jl 0x2acac
movl $0x1, %r14d
movl $0x1, %ebx
leaq 0x3bb0(%rip), %rcx      # 0x2e792
movq -0x48(%rbp), %rax
testq %rax, %rax
cmoveq %rcx, %rax
movb (%rax,%rbx), %al
movzbl %al, %ecx
cmpl $0x2b, %ecx
jg 0x2ac19
cmpl $0x28, %ecx
je 0x2ac2e
cmpl $0x29, %ecx
jne 0x2ac48
cmpl $0x2, %r14d
jl 0x2ae41
decl %r14d
movq %r13, %rdi
movl $0x29, %esi
jmp 0x2ac4e
cmpl $0x2c, %ecx
jne 0x2ac40
cmpl $0x2, %r14d
jl 0x2ac6c
movq %r13, %rdi
movl $0x2c, %esi
jmp 0x2ac4e
movq %r13, %rdi
movl $0x28, %esi
callq 0xe3fa
incl %r14d
jmp 0x2ac53
cmpl $0xff, %ecx
je 0x2acac
movsbl %al, %esi
movq %r13, %rdi
callq 0xe3fa
incq %rbx
movslq -0x4c(%rbp), %rax
cmpq %rax, %rbx
leaq 0x3b2e(%rip), %rcx      # 0x2e792
jl 0x2abe2
jmp 0x2acac
cmpl $0x1, %r14d
jne 0x2aeaa
cmpl $0x0, 0x4(%r13)
jne 0x2ac8d
movq (%r15), %rdi
movq %r12, %rsi
leaq 0xb737(%rip), %rdx      # 0x363c1
callq *0x50(%rdi)
leaq -0xb0(%rbp), %rdi
movq %r13, %rsi
callq 0xbd8f
movl $0x1, %r14d
callq 0xe665
movq %rax, %r13
jmp 0x2ac53
testq %r13, %r13
movq %r15, %rbx
movq -0x38(%rbp), %r14
je 0x2acc0
movq %r13, %rdi
callq 0xe7ba
movq -0x30(%rbp), %r15
movq 0x10(%r14), %rax
cmpq -0xa0(%rbp), %rax
je 0x2ace1
movq (%rbx), %rdi
movq %r12, %rsi
leaq 0xb709(%rip), %rdx      # 0x363e7
callq *0x50(%rdi)
movq (%r14), %r14
testq %r14, %r14
leaq 0x3aa4(%rip), %r12      # 0x2e792
je 0x2ad8a
movq %r15, %rbx
movq -0xb0(%rbp), %r15
movq 0x8(%r14), %rax
movq %rax, -0x78(%rbp)
movq %rbx, %r12
movq 0x8(%r15), %rbx
callq 0xe665
movq %rax, %r13
leaq -0x60(%rbp), %rdi
callq 0xe274
leaq -0x60(%rbp), %rdi
movq %rbx, %rsi
movq %r12, %rbx
leaq 0x3a63(%rip), %r12      # 0x2e792
leaq -0x1ba80(%rip), %rdx    # 0xf2b6
callq 0xf507
movq -0x58(%rbp), %rdx
testq %rdx, %rdx
cmoveq %r12, %rdx
movl -0x5c(%rbp), %ecx
movq %r13, %rdi
movq -0x40(%rbp), %rsi
movq %rbx, %r8
callq 0x2a933
leaq -0x60(%rbp), %rdi
callq 0xe772
leaq -0xf8(%rbp), %rdi
movq -0x78(%rbp), %rsi
movq %r13, %rdx
movl $0x1, %ecx
callq 0xc56c
movq 0x18(%r14), %r14
movq 0x18(%r15), %r15
testq %r14, %r14
jne 0x2acfe
movq -0x38(%rbp), %rax
movq 0x30(%rax), %rdx
testq %rdx, %rdx
cmoveq %r12, %rdx
movl 0x2c(%rax), %ecx
movq -0x70(%rbp), %rbx
movq %rbx, %rdi
movq -0x40(%rbp), %r14
movq %r14, %rsi
leaq -0xf8(%rbp), %r13
movq %r13, %r8
callq 0x2a933
leaq -0xb0(%rbp), %rdi
movl $0x1, %esi
callq 0xbd25
movq %r13, %rdi
xorl %esi, %esi
movl $0x1, %edx
callq 0xc4de
leaq -0x88(%rbp), %rdi
callq 0xe772
leaq -0x50(%rbp), %rdi
callq 0xe772
movq -0x68(%rbp), %r15
jmp 0x2aa57
movq 0x8(%r13), %rdx
movl 0x4(%r13), %ecx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x2a727
movq %r12, %r13
movq %rbx, %rdi
movl $0x22, %esi
callq 0xe3fa
jmp 0x2aa57
movq 0x8(%r12), %rdx
movl 0x4(%r12), %ecx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x2a727
movq %r13, %rdi
callq 0xe772
jmp 0x2aa57
cmpl $0x1, %r14d
jne 0x2af26
cmpl $0x0, 0x4(%r13)
movq %r15, %rbx
movq -0x38(%rbp), %r14
jle 0x2ae6d
leaq -0xb0(%rbp), %rdi
movq %r13, %rsi
callq 0xbd8f
jmp 0x2acc0
cmpq $0x0, -0xa0(%rbp)
je 0x2acb8
movq (%rbx), %rdi
movq %r12, %rsi
leaq 0xb539(%rip), %rdx      # 0x363c1
callq *0x50(%rdi)
jmp 0x2acb8
movq %r15, %rdi
callq 0xb112
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x34bf(%rip), %rdi      # 0x2e370
leaq 0xb38d(%rip), %rsi      # 0x36245
leaq 0xb4a1(%rip), %rcx      # 0x36360
movl $0x21d, %edx            # imm = 0x21D
callq 0xa0b0
leaq 0x34a0(%rip), %rdi      # 0x2e370
leaq 0xb36e(%rip), %rsi      # 0x36245
leaq 0xb482(%rip), %rcx      # 0x36360
movl $0x277, %edx            # imm = 0x277
callq 0xa0b0
leaq 0x3b51(%rip), %rdi      # 0x2ea40
leaq 0xb34f(%rip), %rsi      # 0x36245
leaq 0xb463(%rip), %rcx      # 0x36360
movl $0x19d, %edx            # imm = 0x19D
callq 0xa0b0
leaq 0x3fcf(%rip), %rdi      # 0x2eedd
leaq 0xb330(%rip), %rsi      # 0x36245
leaq 0xb444(%rip), %rcx      # 0x36360
movl $0x19f, %edx            # imm = 0x19F
callq 0xa0b0
leaq 0x3443(%rip), %rdi      # 0x2e370
leaq 0xb311(%rip), %rsi      # 0x36245
leaq 0xb425(%rip), %rcx      # 0x36360
movl $0x232, %edx            # imm = 0x232
callq 0xa0b0