
#include <malloc.h>
#include <ctype.h>
#include <stdbool.h>
#include <string.h>

typedef struct _parse_c_ {
	char name[255];
		// including function in target
	struct _parse_c_ *icld;
	struct _parse_c_ *next;
}	FUNC_LIST, *PFUNC_LIST;

typedef struct _def_arg_list_ {
	char name[10];
	int index;
	struct _def_arg_list_ *next;
}	DEF_ARG_LIST, *PDEF_ARG_LIST;

typedef struct _def_macro_list_ {

	/*
		0: Standard characters
		1: Macro Variable
		2: Pasting Function (##)
		3: Macro Variable Pasting Function ( var## )
	*/
	int processor;

	/*
		Macro Variable index number
		(Define argument index number)
	*/
	int index;

	struct _def_macro_list_ *next;
	char ch;

}	DEF_MACRO_LIST, *PDEF_MACRO_LIST;

typedef struct _parse_def_ {
	char name[255];
	int index;
	DEF_ARG_LIST *dal;
	DEF_MACRO_LIST *dml;
	struct _parse_def_ *next;
}	DEF_LIST, *PDEF_LIST;

typedef struct _line_ {
	struct _line_ *next;
	char *pointer;
}	LINE_LIST, *PLINE_LIST;

DEF_LIST *create_deflist()
{
	DEF_LIST *deflist = (DEF_LIST *)malloc(sizeof(DEF_LIST));
	deflist->next = 0;
	deflist->dal = 0;
	return deflist;
}

DEF_ARG_LIST *create_defarglist()
{
	DEF_ARG_LIST *deflist = (DEF_ARG_LIST *)malloc(sizeof(DEF_ARG_LIST));
	deflist->index = 0;
	deflist->next = 0;
	return deflist;
}

DEF_MACRO_LIST *create_macrolist()
{
	DEF_MACRO_LIST *macrolist = (DEF_MACRO_LIST *)malloc(sizeof(DEF_MACRO_LIST));
	macrolist->next = 0;
	macrolist->index = 0;
	macrolist->processor = 0;
	macrolist->ch = 0;
	return macrolist;
}

/*
	Parse define syntax
*/
PDEF_LIST parse_define(PLINE_LIST lines)
{
	LINE_LIST *current = lines;
	DEF_LIST *deflist = create_deflist();
	DEF_LIST *recentdef = deflist;
	char *pointerptr;
	int index = 0;

	//
	//	Search Define Structure
	//
	do 
	{
		const char *pointer = current->pointer;

		if (*pointer++ == '#')
		{
			const char *str_def = "define";

			for( ; *str_def; str_def++)
			{
				if (*str_def != *pointer++)
				{
					break;
				}
			}

			//
			//	This is not define format.
			//
			if (*str_def)
			{
				continue;
			}

			//
			//	Skip White space
			//
			for( ; isspace(*pointer); pointer++)
				;

			//
			//	Get name
			//
			for(pointerptr = recentdef->name ; isalnum(*pointer) ||
				   *pointer == '$'   ||
				   *pointer == '_'      ; pointer++)
			{
				*pointerptr++ = *pointer;
			}

			*pointerptr = 0;

			//
			//	Check macro
			//
			if (*pointer++ == '(')
			{
				DEF_ARG_LIST *dal = create_defarglist();
				DEF_ARG_LIST *recentdal = dal, *prerecentdal = 0;
				int index_dal = 0;

				//
				//	Search argument
				//
				do
				{
					for( ; isspace(*pointer); pointer++)
						;
					
					for(pointerptr = recentdal->name ; isalnum(*pointer) ||
						   *pointer == '$'   ||
						   *pointer == '_'      ; pointer++)
					{
						*pointerptr++ = *pointer;
					}

					*pointerptr = 0;

					for( ; isspace(*pointer); pointer++)
						;

					if (*pointer == ',')
						pointer++;

					recentdal->index = index_dal;
					recentdal->next = create_defarglist();
					prerecentdal = recentdal;
					recentdal = recentdal->next;
					recentdal->next = 0;

				} while(*pointer != ')');

				if (prerecentdal) 
				{
					free(prerecentdal->next);
					recentdal->next = 0;
					recentdef->dal = dal;
				}

				for( ; isspace(*pointer); pointer++)
					;

				/*
					Parsing Define Format
				*/
				{
					DEF_MACRO_LIST *dml = create_macrolist();
					DEF_MACRO_LIST *recentdml = dml, *prerecnetdml = 0;
					int index_dml = 0;

					for( ; *pointer; pointer++)
					{
						if (isalnum(*pointer) ||
						   *pointer == '$'   ||
						   *pointer == '_'      )
						{
							char arg_search[10];
							const char *t_pointer = pointer;
							int index;
							bool is_exist = false;

							for(pointerptr = arg_search ; isalnum(*pointer) ||
								   *pointer == '$'   ||
								   *pointer == '_'      ; pointer++)
							{
								*pointerptr++ = *pointer;
							}
							
							*pointerptr = 0;

							//
							//	Search argument
							//
							for (recentdal = dal;
								recentdal; recentdal = recentdal->next)
							{
								if (!strcmp(arg_search, recentdal->name))
								{
									is_exist = true;
									index = recentdal->index;
								}
							}

							if (true == is_exist)
							{
								dml->index = index;
								dml->processor = 1;

								if ( * (pointer + 0) == '#' &&
									 * (pointer + 1) == '#'    )
								{
									dml->processor = 3;
									pointer++;
								}
							}
							else
							{
								pointer = t_pointer;
								goto NON_EXIST;
							}
						}
						else if (*pointer == '#')
						{
						PASTING_PROC:
							if (* (pointer + 1) == '#')
							{
								dml->processor = 2;
								pointer++;
							}
						}
						else
						{
						NON_EXIST:
							if (isspace(*pointer))
								continue;
							recentdml->ch = *pointer;
						}

						recentdml->index = index_dml++;
						recentdml->next = create_macrolist();
						prerecnetdml = recentdml;
						recentdml = recentdml->next;
					}

					if (prerecnetdml)
					{
						free(prerecnetdml);
						recentdml->next = 0;
						recentdef->dml = dml;
					}
				}
			}

			recentdef->index = index++;
			recentdef->next = create_deflist();
			recentdef = recentdef->next;
		}

		free(recentdef->next);
		recentdef->next = 0;
		current = current->next;

	} while (current);

	return deflist;
}

int main()
{
	LINE_LIST *ll = (LINE_LIST *) malloc(sizeof(LINE_LIST));
	ll->pointer = "#define pussy_loli(asdf, abcf) abd##tfs ## abcf##dc asdf";
	ll->next = 0;
	
	parse_define(ll);
}