#include #include #include "eo_tokenizer.h" static void _eo_tokenizer_abort(Eo_Tokenizer *toknz, const char *file, const char* fct, int line, const char *fmt, ...) { va_list ap; va_start (ap, fmt); eina_log_vprint(_eo_tokenizer_log_dom, EINA_LOG_LEVEL_ERR, file, fct, line, fmt, ap); va_end(ap); fprintf(stderr, " toknz[%d] n:%d l:%d p:%d pe:%d ts:%d te:%d act:%d\n", toknz->cs, toknz->current_nesting, toknz->current_line, (toknz->p - toknz->buf), (toknz->pe - toknz->buf), toknz->ts, toknz->te, toknz->act); exit(EXIT_FAILURE); } #define ABORT(toknz, ...) \ _eo_tokenizer_abort(toknz, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); static const char* _eo_tokenizer_token_get(Eo_Tokenizer *toknz, char *p) { if (toknz->saved.tok == NULL) ABORT(toknz, "toknz->saved.tok is NULL"); int l = (p - toknz->saved.tok); char d[BUFSIZE]; memcpy(d, toknz->saved.tok, l); d[l] = '\0'; toknz->saved.tok = NULL; DBG("token : >%s<", d); return eina_stringshare_add(d); } static Eo_Class_Def* _eo_tokenizer_class_get(Eo_Tokenizer *toknz, char *p) { Eo_Class_Def *kls = calloc(1, sizeof(Eo_Class_Def)); if (kls == NULL) ABORT(toknz, "calloc Eo_Class_Def failure"); kls->name = _eo_tokenizer_token_get(toknz, p); return kls; } static Eo_Property_Def* _eo_tokenizer_property_get(Eo_Tokenizer *toknz, char *p) { Eo_Property_Def *prop = calloc(1, sizeof(Eo_Property_Def)); if (prop == NULL) ABORT(toknz, "calloc Eo_Property_Def failure"); prop->name = _eo_tokenizer_token_get(toknz, p); return prop; } static Eo_Param_Def* _eo_tokenizer_param_get(Eo_Tokenizer *toknz, char *p) { char *s; char buf[BUFSIZE]; Eo_Param_Def *param = calloc(1, sizeof(Eo_Param_Def)); if (param == NULL) ABORT(toknz, "calloc Eo_Param_Def failure"); for (s = p; s >= toknz->saved.tok; s--) { if ((*s == ' ') || (*s == '*')) break; } if (s == toknz->saved.tok) ABORT(toknz, "wrong parameter: %s", _eo_tokenizer_token_get(toknz, p)); param->type = _eo_tokenizer_token_get(toknz, s+1); toknz->saved.tok = (s + 1); param->name = _eo_tokenizer_token_get(toknz, p); return param; } static Eo_Accessor_Def * _eo_tokenizer_accessor_get(Eo_Tokenizer *toknz, Eo_Accessor_Type type) { Eo_Accessor_Def *accessor = calloc(1, sizeof(Eo_Accessor_Def)); if (accessor == NULL) ABORT(toknz, "calloc Eo_Accessor_Def failure"); accessor->type = type; return accessor; } %%{ machine common; access toknz->; variable p toknz->p; variable pe toknz->pe; variable eof toknz->eof; action inc_line { toknz->current_line += 1; DBG("inc[%d] %d", toknz->cs, toknz->current_line); } action save_line { toknz->saved.line = toknz->current_line; DBG("save line[%d] %d", toknz->cs, toknz->current_line); } action save_fpc { toknz->saved.tok = fpc; DBG("save token[%d] %p %c", toknz->cs, fpc, *fpc); } action show_comment { DBG("comment[%d] line%03d:%03d", toknz->cs, toknz->saved.line, toknz->current_line); } action show_ignore { DBG("ignore[%d] line:%d", toknz->cs, toknz->current_line); } action show_error { DBG("error[%d]", toknz->cs); char *s, *d; char buf[BUFSIZE]; for (s = fpc, d = buf; (s <= toknz->pe); s++) { if ((*s == '\r') || (*s == '\n')) break; *d++ = *s; } *d = '\0'; ERR("error nesting:%d line:%d : %s", toknz->current_nesting, toknz->current_line, buf); toknz->cs = eo_tokenizer_error; fbreak; /* necessary to stop scanners */ } cr = '\n'; cr_neg = [^\n]; ws = [ \t\r]; newline = cr @inc_line; ignore = (0x00..0x20 - cr)+ newline?; alnum_u = alnum | '_'; alpha_u = alpha | '_'; ident = alpha+ >save_fpc (alnum | '_' )+; eo_comment = "/*@" ignore* alnum_u >save_fpc ( any | '\n' @inc_line )* :>> "*/"; c_comment = "/*" ( any | '\n' @inc_line )* :>> "*/"; cpp_comment = "//" (any - cr)* newline; comment = ( c_comment | cpp_comment ) > save_line; end_statement = ';'; begin_def = '{'; end_def = '}' end_statement; begin_list = '('; end_list = ')'; list_separator = ','; }%% %%{ machine eo_tokenizer; include common; write data; ###### TOKENIZE ACCESSOR action end_accessor_comment { if (toknz->tmp.accessor->comment != NULL) ABORT(toknz, "accessor has already a comment"); toknz->tmp.accessor->comment = _eo_tokenizer_token_get(toknz, fpc-1); } action end_rettype { if (toknz->tmp.accessor->ret.type != NULL) ABORT(toknz, "accessor has already a rettype"); toknz->tmp.accessor->ret.type = _eo_tokenizer_token_get(toknz, fpc); } action end_rettype_comment { if (toknz->tmp.accessor->ret.comment != NULL) ABORT(toknz, "accessor rettype has already a comment"); toknz->tmp.accessor->ret.comment = _eo_tokenizer_token_get(toknz, fpc-2); } action end_legacy_name { const char *legacy = _eo_tokenizer_token_get(toknz, fpc); toknz->tmp.accessor->legacies = eina_list_append(toknz->tmp.accessor->legacies, legacy); } action end_accessor { INF(" }"); toknz->tmp.prop->accessors = eina_list_append(toknz->tmp.prop->accessors, toknz->tmp.accessor); toknz->tmp.accessor = NULL; toknz->current_nesting--; fgoto tokenize_property; } rettype_comment = ws* eo_comment %end_rettype_comment; rettype = 'rettype' ws+ '=' ws+ alpha+ >save_fpc (alnum_u | '*' | ws )+ %end_rettype end_statement rettype_comment?; legacy_item = ident %end_legacy_name ignore*; legacy_item_next = list_separator ignore* legacy_item; legacies = 'legacy' ignore* begin_def ignore* (legacy_item legacy_item_next*)? end_def; tokenize_accessor := |* ignore+; #=> show_ignore; eo_comment => end_accessor_comment; comment => show_comment; rettype; legacies; end_def => end_accessor; any => show_error; *|; ###### TOKENIZE PARAMS action end_param_comment { const char *c = _eo_tokenizer_token_get(toknz, fpc-2); if (toknz->tmp.param == NULL) ABORT(toknz, "no parameter set to associate this comment to: %s", c); toknz->tmp.param->comment = c; toknz->tmp.prop->params = eina_list_append(toknz->tmp.prop->params, toknz->tmp.param); toknz->tmp.param = NULL; } action end_param { toknz->tmp.param = _eo_tokenizer_param_get(toknz, fpc); INF(" %s : %s", toknz->tmp.param->name, toknz->tmp.param->type); } action end_params { INF(" }"); if (toknz->tmp.param != NULL) toknz->tmp.prop->params = eina_list_append(toknz->tmp.prop->params, toknz->tmp.param); toknz->tmp.param = NULL; toknz->current_nesting--; fgoto tokenize_property; } param_comment = ws* eo_comment %end_param_comment; param = alpha+ >save_fpc (alnum_u | '*' | ws )+ %end_param end_statement param_comment?; tokenize_params := |* ignore+; #=> show_ignore; comment => show_comment; param; end_def => end_params; any => show_error; *|; ###### TOKENIZE PROPERTY action begin_property_get { INF(" get {"); toknz->tmp.accessor = _eo_tokenizer_accessor_get(toknz, GETTER); toknz->current_nesting++; fgoto tokenize_accessor; } action begin_property_set { INF(" set {"); toknz->tmp.accessor = _eo_tokenizer_accessor_get(toknz, SETTER); toknz->current_nesting++; fgoto tokenize_accessor; } action begin_property_params { INF(" params {"); toknz->current_nesting++; fgoto tokenize_params; } action end_property { if (eina_list_count(toknz->tmp.prop->params) == 0) WRN("property %s has no parameters.", toknz->tmp.prop->name); if (eina_list_count(toknz->tmp.prop->accessors) == 0) WRN("property %s has no accessors.", toknz->tmp.prop->name); INF(" }", toknz->tmp.prop->name); toknz->tmp.kls->properties = eina_list_append(toknz->tmp.kls->properties, toknz->tmp.prop); toknz->tmp.prop = NULL; toknz->current_nesting--; fgoto tokenize_properties; } get = 'get' ws* begin_def; set = 'set' ws* begin_def; params = 'params' ws* begin_def; tokenize_property := |* ignore+; #=> show_ignore; comment => show_comment; get => begin_property_get; set => begin_property_set; params => begin_property_params; end_def => end_property; any => show_error; *|; ###### TOKENIZE PROPERTIES action end_prop_name { Eo_Property_Def *prop = _eo_tokenizer_property_get(toknz); prop->name = _eo_tokenizer_token_get(toknz, fpc-1); } action begin_property { INF(" %s {", toknz->tmp.prop->name); toknz->current_nesting++; fgoto tokenize_property; } action end_property_name { if (toknz->tmp.prop != NULL) ABORT(toknz, "there is a pending property definition %s", toknz->tmp.prop->name); toknz->tmp.prop = _eo_tokenizer_property_get(toknz, fpc); } action end_properties { INF(" }"); toknz->current_nesting--; fgoto tokenize_class; } begin_property = ident %end_property_name ignore* begin_def; tokenize_properties := |* ignore+; #=> show_ignore; comment => show_comment; begin_property => begin_property; end_def => end_properties; any => show_error; *|; ###### TOKENIZE CLASS action end_class_comment { if (toknz->tmp.kls->comment != NULL) ABORT(toknz, "class %s has already a comment", toknz->tmp.kls->name); toknz->tmp.kls->comment = _eo_tokenizer_token_get(toknz, fpc-1); } action end_inherit_name { const char *base = _eo_tokenizer_token_get(toknz, fpc); toknz->tmp.kls->inherits = eina_list_append(toknz->tmp.kls->inherits, base); } action begin_properties { INF(" properties {"); toknz->current_nesting++; fgoto tokenize_properties; } action begin_methods { INF(" begin methods"); toknz->current_nesting++; /* fgoto tokenize_methods; */ } action end_class { INF("end class: %s", toknz->tmp.kls->name); toknz->classes = eina_list_append(toknz->classes, toknz->tmp.kls); toknz->tmp.kls = NULL; toknz->current_nesting--; fgoto main; } inherit_item = ident %end_inherit_name ignore*; inherit_item_next = list_separator ignore* inherit_item; inherits = 'inherits' ignore* begin_def ignore* (inherit_item inherit_item_next*)? end_def; properties = 'properties' ignore* begin_def; methods = 'methods' ignore* begin_def; tokenize_class := |* ignore+; #=> show_ignore; eo_comment => end_class_comment; comment => show_comment; inherits; properties => begin_properties; methods => begin_methods; end_def => end_class; any => show_error; *|; ###### TOP LEVEL action begin_class { INF("begin class: %s", toknz->tmp.kls->name); toknz->current_nesting++; fgoto tokenize_class; } action end_class_name { if (toknz->tmp.kls != NULL) ABORT(toknz, "there is a pending class definition %s", toknz->tmp.kls->name); toknz->tmp.kls = _eo_tokenizer_class_get(toknz, fpc); } begin_class = ident %end_class_name ignore* begin_def; main := |* ignore+; #=> show_ignore; comment => show_comment; begin_class => begin_class; any => show_error; *|; }%% Eina_Bool eo_tokenizer_walk(Eo_Tokenizer *toknz, const char *source) { INF("tokenize %s...", source); toknz->source = eina_stringshare_add(source); FILE *stream; int done = 0; int have = 0; int offset = 0; stream = fopen(toknz->source, "r"); if (!stream) { ERR("unable to read in %s", toknz->source); return EINA_FALSE; } %% write init; while (!done) { int len; int space; toknz->p = toknz->buf + have; space = BUFSIZE - have; if (space == 0) { fclose(stream); ABORT(toknz, "out of buffer space"); } len = fread(toknz->p, 1, space, stream); if (len == 0) break; toknz->pe = toknz->p + len; if (len < space) { toknz->eof = toknz->pe; done = 1; } %% write exec; if ( toknz->cs == %%{ write error; }%% ) { ERR("wrong termination"); break; } if ( toknz->ts == 0 ) have = 0; else { DBG("move data and pointers before buffer feed"); have = toknz->pe - toknz->ts; offset = toknz->ts - toknz->buf; memmove(toknz->buf, toknz->ts, have); toknz->te -= offset; toknz->ts = toknz->buf; } if (toknz->saved.tok != NULL) { if ((have == 0) || ((toknz->saved.tok - offset) < toknz->buf)) { WRN("reset lost saved token %p", toknz->saved.tok); toknz->saved.tok = NULL; } else toknz->saved.tok -= offset; } } fclose(stream); return EINA_TRUE; } Eo_Tokenizer* eo_tokenizer_get(void) { Eo_Tokenizer *toknz = calloc(1, sizeof(Eo_Tokenizer)); if (!toknz) return NULL; toknz->ts = NULL; toknz->te = NULL; /* toknz->top = 0; */ toknz->source = NULL; toknz->max_nesting = 10; toknz->current_line = 1; toknz->current_nesting = 0; toknz->saved.tok = NULL; toknz->saved.line = 0; toknz->classes = NULL; return toknz; } void eo_tokenizer_dump(Eo_Tokenizer *toknz) { const char *s; Eina_List *k, *l; Eo_Class_Def *kls; EINA_LIST_FOREACH(toknz->classes, k, kls) { printf("Class: %s (%s)\n", kls->name, (kls->comment ? kls->comment : "-")); printf(" inherits from :"); EINA_LIST_FOREACH(kls->inherits, l, s) printf(" %s", s); printf("\n"); } } static void _eo_tokenizer_ret_free(Eo_Ret_Def *ret) { if (ret->type) eina_stringshare_del(ret->type); if (ret->comment) eina_stringshare_del(ret->comment); /* do not free */ } static void _eo_tokenizer_param_free(Eo_Param_Def *param) { if (param->type) eina_stringshare_del(param->type); if (param->name) eina_stringshare_del(param->name); if (param->comment) eina_stringshare_del(param->comment); free(param); } static void _eo_tokenizer_accessor_free(Eo_Accessor_Def *accessor) { const char *s; Eina_List *l; if (accessor->comment) eina_stringshare_del(accessor->comment); EINA_LIST_FOREACH(accessor->legacies, l, s) if (s) eina_stringshare_del(s); _eo_tokenizer_ret_free(&accessor->ret); free(accessor); } static void _eo_tokenizer_property_def_free(Eo_Property_Def *prop) { Eo_Param_Def *param; Eo_Accessor_Def *accessor; if (prop->name) eina_stringshare_del(prop->name); EINA_LIST_FREE(prop->params, param) _eo_tokenizer_param_free(param); EINA_LIST_FREE(prop->accessors, accessor) _eo_tokenizer_accessor_free(accessor); free(prop); } static void _eo_tokenizer_method_def_free(Eo_Method_Def *meth) { Eo_Param_Def *param; _eo_tokenizer_ret_free(&meth->ret); if (meth->name) eina_stringshare_del(meth->name); if (meth->comment) eina_stringshare_del(meth->comment); EINA_LIST_FREE(meth->params, param) _eo_tokenizer_param_free(param); free(meth); } static void _eo_tokenizer_class_def_free(Eo_Class_Def *kls) { const char *s; Eina_List *l; Eo_Property_Def *prop; Eo_Method_Def *meth; if (kls->name) eina_stringshare_del(kls->name); if (kls->comment) eina_stringshare_del(kls->comment); EINA_LIST_FOREACH(kls->inherits, l, s) if (s) eina_stringshare_del(s); EINA_LIST_FREE(kls->properties, prop) _eo_tokenizer_property_def_free(prop); EINA_LIST_FREE(kls->methods, meth) _eo_tokenizer_method_def_free(meth); free(kls); } void eo_tokenizer_free(Eo_Tokenizer *toknz) { Eo_Class_Def *kls; if (toknz->source) eina_stringshare_del(toknz->source); EINA_LIST_FREE(toknz->classes, kls) _eo_tokenizer_class_def_free(kls); free(toknz); }