293 lines
9.3 KiB
C
293 lines
9.3 KiB
C
|
//#define META_DEMO
|
||
|
|
||
|
#include "v4k.h"
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
static
|
||
|
char *reformat(const char *text, const char *blacklist, const char *separator) {
|
||
|
char **list = strsplit(text, blacklist);
|
||
|
char *joint = strjoin(list, separator);
|
||
|
return joint;
|
||
|
}
|
||
|
|
||
|
const char *c_symbols = "{},>&/+=;:"; // "(){}[].,><&*/+=;:!~";
|
||
|
const char *c_symbols_extra = "{},>&/+=;:[]()"; // "(){}[].,><&*/+=;:!~";
|
||
|
const char *c_keywords[] = { "const","long","signed","unsigned","typedef" }; int num_keywords = 4;
|
||
|
|
||
|
typedef struct meta {
|
||
|
const char *name;
|
||
|
const char *tags;
|
||
|
} meta;
|
||
|
meta metas[2048] = {
|
||
|
/*00*/ {"typedef", ""},
|
||
|
/*01*/ {"enum", ""},
|
||
|
/*02*/ {"struct", ""},
|
||
|
/*03*/ {"function", ""},
|
||
|
|
||
|
/*04*/ {"bool", "default 0"},
|
||
|
/*05*/ {"false", "default 0 bits 1"},
|
||
|
/*06*/ {"true", "default 1 bits 1"},
|
||
|
|
||
|
/*07*/ {"char", "default 0 bits 8"},
|
||
|
/*08*/ {"int", "default 0"},
|
||
|
/*09*/ {"float", "default 0 bits 32"},
|
||
|
/*10*/ {"double", "default 0 bits 64"},
|
||
|
|
||
|
/*11*/ {"int8_t", "default 0 bits 8"},
|
||
|
/*12*/ {"int16_t", "default 0 bits 16"},
|
||
|
/*13*/ {"int32_t", "default 0 bits 32"},
|
||
|
/*14*/ {"int64_t", "default 0 bits 64"},
|
||
|
/*15*/ {"uint8_t", "default 0 bits 8 signed 0"},
|
||
|
/*16*/ {"uint16_t", "default 0 bits 16 signed 0"},
|
||
|
/*17*/ {"uint32_t", "default 0 bits 32 signed 0"},
|
||
|
/*18*/ {"uint64_t", "default 0 bits 64 signed 0"},
|
||
|
};
|
||
|
int meta_count = 19;
|
||
|
const char *meta_last_name = 0;
|
||
|
const char *meta_last_struct = 0;
|
||
|
|
||
|
meta* meta_find(const char *name) {
|
||
|
for( int i = 0; i < meta_count; ++i ) {
|
||
|
if( 0 == strcmp(name, metas[i].name) ) return &metas[i];
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
meta* meta_add(const char *name, const char *subtype, const char *tags ) {
|
||
|
{ meta *t = meta_find(name); if( t ) return t; }
|
||
|
|
||
|
if( meta_count >= 2048 ) return 0;
|
||
|
|
||
|
meta t = { STRDUP(name), reformat(STRDUP(tags), " ", " ") };
|
||
|
metas[meta_count] = t;
|
||
|
meta_last_struct = !strcmp(subtype, "struct") ? name : meta_last_struct;
|
||
|
meta_last_name = !strcmp(subtype, "struct") || !strcmp(subtype, "enum") || !strcmp(subtype, "typedef") ? name : subtype;
|
||
|
return &metas[meta_count++];
|
||
|
}
|
||
|
char* meta_find_value(const char *name, const char *prop) {
|
||
|
meta *t = meta_find(name);
|
||
|
if( !t ) return 0;
|
||
|
char *found = strstr(t->tags, prop);
|
||
|
if( !found ) return 0;
|
||
|
|
||
|
static char copy[256] = {0}; // @fixme
|
||
|
strcpy(copy, found + strlen(prop) + 1);
|
||
|
for(int i=0; copy[i]; ++i) if(copy[i]==' ') { copy[i] = 0; break; }
|
||
|
return copy;
|
||
|
}
|
||
|
void meta_inspectf(FILE *fp) {
|
||
|
if( fp ) {
|
||
|
char buf[255+1];
|
||
|
|
||
|
while(fgets(buf, 255, fp)) {
|
||
|
char *mark = strstr(buf, "//""M");
|
||
|
if( !mark ) continue;
|
||
|
char *tags = mark + 3;
|
||
|
|
||
|
// must reset last_struct
|
||
|
if( strstr(buf, "typedef") ) {
|
||
|
meta_last_struct = 0; // typedef is a special case
|
||
|
}
|
||
|
|
||
|
// remove symbols
|
||
|
for( int i = 0; buf[i]; ++i ) {
|
||
|
// symbols off
|
||
|
if(strchr(&buf[i] < tags ? c_symbols : c_symbols_extra, buf[i])) { buf[i] = ' '; continue; }
|
||
|
}
|
||
|
|
||
|
// remove leading whitespaces
|
||
|
char *spc = buf;
|
||
|
while( spc && spc[0] && spc[0] <= 32 ) ++spc;
|
||
|
|
||
|
// remove trailing linefeeds and whitespaces
|
||
|
int len = strlen(buf);
|
||
|
while( len > 0 && buf[len-1] <= 32 ) buf[--len] = 0;
|
||
|
|
||
|
// split buffer into left|right buffers
|
||
|
char *left = spc, *right = tags; right[-1] = 0;
|
||
|
|
||
|
// remove left keywords
|
||
|
for( int i = 0; left[i]; ++i ) {
|
||
|
for(int j = 0; j < sizeof(c_keywords)/sizeof(0[c_keywords]); ++j) {
|
||
|
int kb = strlen(left+i);
|
||
|
int kl = strlen(c_keywords[j]);
|
||
|
if( kl <= kb && !memcmp(left+i, c_keywords[j], kl) ) {
|
||
|
memset(left+i, ' ', kl);
|
||
|
i += kl;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// debug
|
||
|
// printf("%s <--> %s\n", left, right);
|
||
|
|
||
|
// add type
|
||
|
const char *meta_name = 0;
|
||
|
const char *meta_t = 0;
|
||
|
const char *meta_val = "";
|
||
|
array(char *) tokens = strsplit(left, " \t");
|
||
|
if(1) for( int i = 0, end = array_count(tokens); i < end; ++i ) {
|
||
|
/**/ if( strstr(tokens[i],"enum") ) meta_last_name = 0, meta_last_struct = 0, meta_t = "enum";
|
||
|
else if( strstr(tokens[i],"struct") ) meta_last_name = 0, meta_last_struct = 0, meta_t = "struct";
|
||
|
else if( strstr(tokens[i],"typedef") ) meta_last_name = 0, meta_last_struct = 0, meta_t = "typedef"; // trimmed. never happens
|
||
|
else if( strchr(tokens[i],'(') ) meta_last_name = 0, meta_last_struct = 0, meta_name = tokens[i], meta_t = "function";
|
||
|
else if( !meta_name ) meta_name = tokens[i];
|
||
|
else if( !meta_t ) meta_t = tokens[i];
|
||
|
}
|
||
|
|
||
|
if( meta_find(meta_name) ) {
|
||
|
const char *swap = meta_name;
|
||
|
meta_name = meta_t;
|
||
|
meta_t = swap;
|
||
|
}
|
||
|
|
||
|
// if !meta_find defer(meta_eval) && emit(warning) && keep(iterating);
|
||
|
|
||
|
bool is_pointer = strstr(meta_name, "*");
|
||
|
meta_name = (char *)reformat(meta_name, "*", "");
|
||
|
char *found_sqr = strstr(meta_name, "[");
|
||
|
int array_len = found_sqr ? atoi(found_sqr+1) : 0;
|
||
|
if( found_sqr ) *found_sqr = 0;
|
||
|
|
||
|
bool is_number = false;
|
||
|
char conv[32] = {0};
|
||
|
double dbl = atof(meta_t);
|
||
|
if(!is_number) { sprintf(conv, "%f", dbl); is_number = !strcmp(conv, meta_t); }
|
||
|
if(!is_number) { sprintf(conv, "%.f", dbl); is_number = !strcmp(conv, meta_t); }
|
||
|
if(is_number) {
|
||
|
meta_val = meta_t;
|
||
|
meta_t = meta_last_name;
|
||
|
}
|
||
|
|
||
|
char hints[256] = {0}, *p = hints;
|
||
|
if( 1 ) p += sprintf(p, "type %s ", meta_t);
|
||
|
if( is_pointer || array_len ) p += sprintf(p, "pointer %d ", 1);
|
||
|
if( array_len ) p += sprintf(p, "count %d ", array_len);
|
||
|
if( 1 ) p += sprintf(p, "%s ", tags);
|
||
|
if( meta_last_struct ) p += sprintf(p, "struct %s ", meta_last_struct);
|
||
|
if( meta_val[0] ) p += sprintf(p, "default %s ", meta_val);
|
||
|
meta_val = hints;
|
||
|
|
||
|
// inherited tags (from super type) at the very end, so overriden tags can be found at first place
|
||
|
if( meta_find(meta_t) )
|
||
|
p += sprintf(p, "%s ", meta_find(meta_t)->tags );
|
||
|
|
||
|
|
||
|
if( !meta_find(meta_name) ) {
|
||
|
meta_add(meta_name, meta_t, meta_val);
|
||
|
|
||
|
meta *t = meta_find(meta_name);
|
||
|
//printf("%s,%s\n", t->name, t->tags);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
// clean state
|
||
|
meta_last_name = 0;
|
||
|
meta_last_struct = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool meta_save(FILE *fp) {
|
||
|
if( fp )
|
||
|
for( int i = 0; i < meta_count; ++i ) {
|
||
|
meta *t = &metas[i];
|
||
|
fprintf(fp, "%s %s\n", t->name, t->tags);
|
||
|
}
|
||
|
return !!fp;
|
||
|
}
|
||
|
bool meta_load(FILE *fp) {
|
||
|
if( fp ) {
|
||
|
meta_count = 0;
|
||
|
meta_last_name = 0;
|
||
|
meta_last_struct = 0;
|
||
|
|
||
|
char buf[2048+1];
|
||
|
while(fgets(buf, 2048, fp)) {
|
||
|
int bl = strlen(buf); while( bl && buf[bl] <= 32) buf[bl--] = 0;
|
||
|
char id[128];
|
||
|
sscanf(buf, "%s", id);
|
||
|
metas[ meta_count ].name = strdup(id);
|
||
|
metas[ meta_count ].tags = strdup(buf+strlen(id)+1);
|
||
|
++meta_count;
|
||
|
}
|
||
|
}
|
||
|
return !!fp;
|
||
|
}
|
||
|
|
||
|
void meta_inspect(const char *name) {
|
||
|
FILE *fp = fopen(name, "rb");
|
||
|
if( !fp ) return;
|
||
|
meta_inspectf(fp);
|
||
|
fclose(fp);
|
||
|
}
|
||
|
bool meta_savefile(const char *name) {
|
||
|
FILE *fp = fopen(name, "wb");
|
||
|
if( !fp ) return false;
|
||
|
meta_save(fp); fclose(fp);
|
||
|
return true;
|
||
|
}
|
||
|
bool meta_loadfile(const char *name) {
|
||
|
FILE *fp = fopen(name, "rb");
|
||
|
if( !fp ) return false;
|
||
|
meta_load(fp); fclose(fp);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef META_DEMO
|
||
|
#pragma once
|
||
|
|
||
|
typedef int my_array[8]; //M
|
||
|
typedef const char *string; //M
|
||
|
|
||
|
typedef enum Fruit { //M bits:8
|
||
|
Banana = -1, //M
|
||
|
Orange = 42 //M
|
||
|
} Fruit;
|
||
|
|
||
|
struct myObject { //M version:100
|
||
|
Fruit meal; //M default:Banana
|
||
|
int32_t hitpoints; //M default:100 zigzag:yes
|
||
|
float shininess; //M default:+3.5e2 min:0 max:1 fixed:yes
|
||
|
string text; //M default:"DEMO"
|
||
|
bool visible; //M bits:1 deprecated:1 version:001
|
||
|
char test; //M serialize:off
|
||
|
};
|
||
|
|
||
|
int print(int); //M const:true
|
||
|
|
||
|
typedef int dummy; //M extra=separators allowed(too)
|
||
|
|
||
|
int main(int argc, const char **argv) {
|
||
|
|
||
|
#ifndef NDEBUG
|
||
|
unlink(__FILE__ ".meta");
|
||
|
#endif
|
||
|
|
||
|
if( meta_loadfile(__FILE__ ".meta") ) {
|
||
|
puts("Loaded .meta file");
|
||
|
} else {
|
||
|
puts("Cannot read .meta file. regenerating...");
|
||
|
meta_inspect(__FILE__);
|
||
|
puts("Saving .meta file...");
|
||
|
meta_savefile(__FILE__ ".meta");
|
||
|
}
|
||
|
|
||
|
meta_save( stdout );
|
||
|
|
||
|
puts(meta_find_value("Orange", "type"));
|
||
|
puts(meta_find_value("Orange", "bits"));
|
||
|
puts(meta_find_value("Orange", "default"));
|
||
|
puts(meta_find_value("visible", "type"));
|
||
|
puts(meta_find_value("shininess", "fixed"));
|
||
|
}
|
||
|
|
||
|
#define main main__
|
||
|
#endif
|