Beispiel #1
0
void expr_test()
{
    int a, b;
    a = 0;
    printf("%d\n", a += 1);
    printf("%d\n", a -= 2);
    printf("%d\n", a *= 31232132);
    printf("%d\n", a /= 4);
    printf("%d\n", a %= 20);
    printf("%d\n", a &= 6);
    printf("%d\n", a ^= 7);
    printf("%d\n", a |= 8);
    printf("%d\n", a >>= 3);
    printf("%d\n", a <<= 4);

    a = 22321;
    b = -22321;
    printf("%d\n", a + 1);
    printf("%d\n", a - 2);
    printf("%d\n", a * 312);
    printf("%d\n", a / 4);
    printf("%d\n", b / 4);
    printf("%d\n", (unsigned)b / 4);
    printf("%d\n", a % 20);
    printf("%d\n", b % 20);
    printf("%d\n", (unsigned)b % 20);
    printf("%d\n", a & 6);
    printf("%d\n", a ^ 7);
    printf("%d\n", a | 8);
    printf("%d\n", a >> 3);
    printf("%d\n", b >> 3);
    printf("%d\n", (unsigned)b >> 3);
    printf("%d\n", a << 4);
    printf("%d\n", ~a);
    printf("%d\n", -a);
    printf("%d\n", +a);

    printf("%d\n", 12 + 1);
    printf("%d\n", 12 - 2);
    printf("%d\n", 12 * 312);
    printf("%d\n", 12 / 4);
    printf("%d\n", 12 % 20);
    printf("%d\n", 12 & 6);
    printf("%d\n", 12 ^ 7);
    printf("%d\n", 12 | 8);
    printf("%d\n", 12 >> 2);
    printf("%d\n", 12 << 4);
    printf("%d\n", ~12);
    printf("%d\n", -12);
    printf("%d\n", +12);
    printf("%d %d %d %d\n", 
           isid('a'), 
           isid('g'), 
           isid('T'), 
           isid('('));
}
Beispiel #2
0
char *
getname(void)			/* scan an identifier */
{
    static char	 str[RMAXWORD+1];
    int  i, lnext;

    lnext = nextc;
    for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = scan())
	str[i] = lnext;
    str[i] = '\0';
    while (isid(lnext))		/* skip rest of name */
	lnext = scan();

    return(str);
}
Beispiel #3
0
std::pair<std::string, token_type> token_iterator::next() {
	static const std::set<std::string> tokens = {
		"++", "--", "<<", ">>", "<=", ">=", "==", "!=", "&&", "||", "^^",
		"+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "|=", "^=", "//", "/*"
	};
	std::string result = next_whitespace_;
	next_whitespace_.erase();
	while (input_ && *input_ && std::isspace(input_->peek())) result += input_->get();
	if (!result.empty() || !input_) return { result, token_type::whitespace };
	while (true) {
		char c = input_->peek();
		if (!*input_) break;
		if (c == '\\') {
			input_->ignore();
			if (input_->get() == '\n') next_whitespace_ += '\n';
			continue;
		}
		if (!result.empty()) {
			if (isid(result[0])) {
				if (!isid(c) && !(c == '.' && isdigit(result[0]))) break;
			} else {
				if (!tokens.count(result + c)) break;
			}
		}
		result += input_->get();
		if (result == "//") {
			std::string c;
			std::getline(*input_, c);
			next_whitespace_ = "\n";
			return { result + c, token_type::comment };
		} else if (result == "/*") {
			while (true) {
				std::string c;
				std::getline(*input_, c, '*');
				result += c + '*';
				if (input_->peek() == '/') {
					result += input_->get();
					return { result, token_type::comment };
				}
			}
		}
	}
	if (!*input_) input_ = 0;
	if (result.empty())               return { result, token_type::whitespace };
	else if (std::isdigit(result[0])) return { result, token_type::number     };
	else if (isid(result[0]))         return { result, token_type::word       };
	else                              return { result, token_type::other      };
}
Beispiel #4
0
char *
setcontext(			/* set a new context path */
	char  *ctx
)
{
    char  *cpp;

    if (ctx == NULL)
	return(context);		/* just asking */
    while (*ctx == CNTXMARK)
	ctx++;				/* skip past marks */
    if (!*ctx) {
	context[0] = '\0';		/* empty means clear context */
	return(context);
    }
    cpp = context;			/* start context with mark */
    *cpp++ = CNTXMARK;
    do {				/* carefully copy new context */
	if (cpp >= context+MAXCNTX)
	    break;			/* just copy what we can */
	if (isid(*ctx))
	    *cpp++ = *ctx++;
	else {
	    *cpp++ = '_'; ctx++;
	}
    } while (*ctx);
    while (cpp[-1] == CNTXMARK)		/* cannot end in context mark */
	cpp--;
    *cpp = '\0';
    return(context);
}
Beispiel #5
0
void lxadv(struct lexer *lx, struct tok *tk)
{
	trim_space(lx);

	if (lx->cur == '\'') {
		strcpy(tk->lexeme, "'");
		tk->kind = TK_QUOTE;
		lxadvch(lx);
	} else if (isid(lx->cur)) {
		if (isdigit(lx->cur))
			get_num(lx, tk);
		else
			get_id(lx, tk);
	} else if (lx->cur == '(') {
		strcpy(tk->lexeme, "(");
		tk->kind = TK_LPAR;
		lxadvch(lx);
	} else if (lx->cur == ')') {
		strcpy(tk->lexeme, ")");
		tk->kind = TK_RPAR;
		lxadvch(lx);
	} else if (lx->cur == '\0' || lx->cur == EOF) {
		tk->kind = TK_EOF;
	}
}
Beispiel #6
0
static void get_id(struct lexer *lx, struct tok *tk)
{
	char *dest = tk->lexeme;
	while (isid(lx->cur))
		*dest++ = lxadvch(lx);
	*dest = '\0';
	tk->kind = TK_ID;
}
Beispiel #7
0
int token(FILE *fp)
{
	int c, state = 0, id_index = 0;
	if (!fp)
		return TOKEN_ERROR;
LOOP:
#define isid(c) (isalnum(c) || (c) == '.' || (c) == '-' || (c) == '_')
	c = fgetc(fp);
	switch(state) {
	case 0:
		if (isspace(c))
			break;
		if (c == EOF)
			return TOKEN_EOF;
		if (c == '(')
			return TOKEN_LP;
		if (c == ')')
			return TOKEN_RP;
		if (c == ',')
			return TOKEN_COMMA;
		if (isid(c)) {
			memset(id, '\0', sizeof(char) * ID_SIZE);
			id[id_index++] = c;
			state = 1;
			break;
		}
		fputs("Unknown character! Duck and cover!\n", stderr);
		return TOKEN_ERROR;
	case 1:
		if (isid(c)) {
			id[id_index++] = c;
			if (id_index == ID_SIZE) {
				fputs("Identifier TL;DR.\n", stderr);
				return TOKEN_ERROR;
			}
		} else {
			ungetc(c, fp);
			return TOKEN_ID;
		}
		break;
	default:
		fputs("State is a lie.\n", stderr);
		return TOKEN_ERROR;
	}
	goto LOOP;
}
Beispiel #8
0
string Editor::getKeyword(){
	fixFmt(true);
	getSel();
	int ln=editCtrl.LineFromChar(selStart);
	int pos=selStart-editCtrl.LineIndex( ln );
	string line=getLine( ln );if( pos>line.size() ) return "";

	//ok, scan back until we have an isapha char preceded by a nonalnum/non '_' char
	for(;;){
		while( pos>0 && ( !isalpha(line[pos]) || isid(line[pos-1]) ) ) --pos;
		if( !isalpha(line[pos]) ) return "";
		int end=pos;while( end<line.size() && isid(line[end]) ) ++end;
		string t=line.substr( pos,end-pos );
		if( keyWordSet.find( t )!=keyWordSet.end() ) return t;
		if( !pos ) return "";
		--pos;
	}
}
Beispiel #9
0
yylex() {
	static int ifdef=0;
	static char *op2[]={"||",  "&&" , ">>", "<<", ">=", "<=", "!=", "=="};
	static int  val2[]={OROR, ANDAND,  RS,   LS,   GE,   LE,   NE,   EQ};
	static char *opc="b\bt\tn\nf\fr\r\\\\";
	extern char fastab[];
	extern char *outp,*inp,*newp; extern int flslvl;
	register char savc, *s; char *skipbl(); int val;
	register char **p2;
	struct symtab {
		char *name;
		char *value;
	} *sp, *lookup();

for (;;) {
	extern int passcom;		/* this crap makes #if's work */
	int opt_passcom = passcom;	/* even with -C option */
	passcom = 0;			/* (else comments make syntax errs) */
	newp=skipbl(newp);
	passcom = opt_passcom;		/* nb: lint uses -C so its useful! */
	if (*inp=='\n') return(stop);	/* end of #if */
	savc= *newp; *newp='\0';
	for (p2=op2+8; --p2>=op2; )	/* check 2-char ops */
		if (0==strcmp(*p2,inp)) {val=val2[p2-op2]; goto ret;}
	s="+-*/%<>&^|?:!~(),";	/* check 1-char ops */
	while (*s) if (*s++== *inp) {val= *--s; goto ret;}
	if (*inp<='9' && *inp>='0') {/* a number */
		if (*inp=='0') yylval= (inp[1]=='x' || inp[1]=='X') ?
			tobinary(inp+2,16) : tobinary(inp+1,8);
		else yylval=tobinary(inp,10);
		val=number;
	} else if (isid(*inp)) {
		if (0==strcmp(inp,"defined")) {ifdef=1; ++flslvl; val=DEFINED;}
		else {
			sp=lookup(inp,-1); if (ifdef!=0) {ifdef=0; --flslvl;}
			yylval= (sp->value==0) ? 0 : 1;
			val=number;
		}
	} else 	if (*inp=='\'') {/* character constant */
		val=number;
		if (inp[1]=='\\') {/* escaped */
			char c; if (newp[-1]=='\'') newp[-1]='\0';
			s=opc;
			while (*s) if (*s++!=inp[2]) ++s; else {yylval= *s; goto ret;}
			if (inp[2]<='9' && inp[2]>='0') yylval=c=tobinary(inp+2,8);
			else yylval=inp[2];
		} else yylval=inp[1];
	} else if (0==strcmp("\\\n",inp)) {*newp=savc; continue;}
	else {
		*newp=savc; pperror("Illegal character %c in preprocessor if", *inp);
		continue;
	}
ret:
	*newp=savc; outp=inp=newp; return(val);
}
}
Beispiel #10
0
static void setuidgid(const char *userarg,
		      const char *grouparg)
{
	if (grouparg)
	{
	gid_t gid = 0;
	struct group *gr;
	
		if (isid(grouparg))
			gid=atoi(grouparg);
		else if ((gr=getgrnam(grouparg)) == 0)
		{
			fprintf(stderr, "Group not found: %s\n", grouparg);
			exit(1);
		}
		else	gid=gr->gr_gid;

		libmail_changegroup(gid);
	}

	if (userarg)
	{
	uid_t	uid;

		if (isid(userarg))
		{
			uid=atoi(userarg);
			libmail_changeuidgid(uid, getgid());
		}
		else
		{
		gid_t	g=getgid(), *gp=0;

			if (grouparg)	gp= &g;
			libmail_changeusername(userarg, gp);
		}
	}
}
Beispiel #11
0
bool CHttpServer::parse_route(String const &line, Route &route)
{
    if (line.empty())
        return false;
    
    const char *s = line.c_str();
    if (*s == '/')
        ++s;
    
    const char *application_begin = s;
    for(; *s != '/' && *s != '\0'; ++s);
    if (*s == '\0')
        return false;
    const char *application_end = s;
    
    const char *model_begin = ++s;
    for(; *s != '/' && *s != '\0'; ++s);
    const char *model_end = s;
    
    route.application.assign(application_begin, application_end);
    route.model.assign(model_begin, model_end);
    
    if (*s == '\0')
        return true;
    
    const char *actionorid_begin = ++s;
    for (; *s != '/' && *s != '\0'; ++s);
    const char *actionorid_end = s;
    
    if (*s == '/')
        ++s;

    String aoi(actionorid_begin, actionorid_end);
    if (isid(aoi)) {
        route.id = aoi;
        route.action = s;
    }
    else {
        route.id = s;
        route.action = aoi;
    }
    
	//const char* frag = strrchr(route.action.c_str(), '#');
	//if (frag)
	//	route.action = route.action.substr(0, frag-route.action.c_str());
	
    return true;
}
Beispiel #12
0
// Return length of leading font id
static int font_id_len(const string& s)
{
    // Font ids have the syntax "[_A-Za-z][-_A-Za-z0-9]*"

    if (s.empty())
	return 0;

    if (s[0] != '_' && !isalpha(s[0]))
	return 0;

    for (int i = 1; i < int(s.length()); i++)
	if (s[i] != '-' && !isid(s[i]))
	    return i;

    return s.length();
}
Beispiel #13
0
	/* load next token of type id */
	const char *token_id(void)
	{
		static char id[NAMELEN];
		char *s;
		int n;

		n = sizeof(id) - 1;
		s = id-1;
		do {
			s++;
			*s = fgetc(f);
			n--;
			if (n <= 0) {
				*s = '\0';
				fprintf(stderr, "Error: name too long: %s...\n", id);
			}
		} while(isid(*s));
		ungetc(*s, f);
		*s = '\0';
		return id;
	}
Beispiel #14
0
int islegal(char *data[],int ln){
	int id=0;
	if (strcmp(data[0], "BSRule") != 0){
		printf("规则语句出现语法错误,规则头应为BSRule,在 %d 行\n",ln);
		return 1;
	}
	if (strcmp(data[1], "http") != 0 &&
		strcmp(data[1], "tcp") != 0 &&
		strcmp(data[1], "udp") != 0 &&
		strcmp(data[1], "tcp") != 0){
		printf("规则语句出现语法错误,协议类型错误,在 %d 行\n",ln);
		return 2;
	}
	if (!isip(data[2]) || !isport(data[3])){
		printf("规则语句出现语法错误,第一部分IP或端口数据错误,在 %d 行\n",ln);
		return 3;
	}
	if (strcmp(data[4],"->")!=0 &&
		strcmp(data[4],"<-")!=0 &&
		strcmp(data[4],"<->")!=0 ){
			printf("规则语句出现语法错误,数据流方向符错误,在 %d 行\n",ln);
			return 4;
	}
	if(!isip(data[5]) || !isport(data[6])){
		printf("规则语句出现语法错误,第二部分IP或端口数据错误,在 %d 行\n",ln);
		return 5;
	}
	if(!isid(data[8])){
		printf("规则语句出现语法错误,规则ID号不合法,在 %d 行\n",ln);
		return 8;
	}
	if(!isuniq(id)){
		id = atoi(data[8]);
		printf("规则语句出现语法错误,规则ID号不唯一,在 %d 行\n",ln);
		return 8;
	}
	return 0;
}
Beispiel #15
0
void Editor::formatStreamLine(){
	string out;
	char cf='0';
	for( int k=0;k<is_line.size(); ){
		int from=k;
		char pf=cf;
		int c=is_line[k],is_sz=is_line.size();
		if( !isgraph( c ) ){
			for( ++k;k<is_sz && !isgraph(is_line[k]);++k ){}
		}else if( !isfmt( c,k+1<is_sz?is_line[k+1]:0 ) ){
			for( ++k;k<is_sz && !isfmt( is_line[k],k+1<is_sz?is_line[k+1]:0 );++k ){}
			cf='6';
		}else if( c==';' ){					//comment?
			k=is_sz;
			cf='4';
		}else if( c=='\"' ){		//string const?
			for( ++k;k<is_sz && is_line[k]!='\"';++k ){}
			if( k<is_sz ) ++k;
			cf='1';
		}else if( isalpha( c ) ){		//ident?
			for( ++k;k<is_sz && isid(is_line[k]);++k ){}
			if( keyWordSet.find( is_line.substr( from,k-from ) )==keyWordSet.end() ) cf='2';
			else cf='3';
		}else if( c=='$' ){
			for( ++k;k<is_sz && isxdigit(is_line[k]);++k ){}
			cf='5';
		}else if( isdigit( c ) ){	//numeric const?
			for( ++k;k<is_sz && isdigit(is_line[k]);++k ){}
			cf='5';
		}
		if( cf!=pf ){
			out+="\\cf";out+=cf;out+=' ';
		}
		out+=is_line.substr( from,k-from );
	}
	if( is_line[0]=='F' && is_line.find( "Function" )==0 ){
		for( int k=8;k<is_line.size();++k ){
			if( isalpha( is_line[k] ) ){
				int start=k;
				for( ++k;k<is_line.size() && isid(is_line[k]);++k ){}
				funcList.insert( is_linenum,is_line.substr( start,k-start ) );
				break;
			}
		}
	}else if( is_line[0]=='T' && is_line.find( "Type" )==0 ){
		for( int k=4;k<is_line.size();++k ){
			if( isalpha( is_line[k] ) ){
				int start=k;
				for( ++k;k<is_line.size() && isid(is_line[k]);++k ){}
				typeList.insert( is_linenum,is_line.substr( start,k-start ) );
				break;
			}
		}
	}else if( is_line[0]=='.' ){
		for( int k=1;k<is_line.size();++k ){
			if( isalpha( is_line[k] ) ){
				int start=k;
				for( ++k;k<is_line.size() && isid(is_line[k]);++k ){}
				labsList.insert( is_linenum,is_line.substr( start,k-start ) );
				break;
			}
		}
	}
	is_line=out+"\\line ";
}
Beispiel #16
0
void
setmgvar(		/* set a variable */
char  *fname,
FILE  *fp,
char  *string
)
{
	char  name[128];
	FILE  *fp2;
	register int  i;
	register char  *s;
	register VARIABLE  *vp;

	if (!strncmp(string, "include=", 8)) {	/* include file */
		if ((s = findfile(string+8, libpath)) == NULL) {
			fprintf(stderr, "%s\n", string);
			fprintf(stderr, "%s: %s: File not found: %s\n",
					progname, fname, string+8);
			quit(1);
		}
		strcpy(name, s);
		mgload(name);
		return;
	}
	s = string;
	i = 0;
	while (i < sizeof(name)-1 && isid(*s))
		name[i++] = *s++;
	name[i] = '\0';
	vp = vlookup(name);
	if (vp != NULL) {
		undefine(vp);
		switch (vp->type) {
		case REAL:
		case FUNCTION:
			if ((*s == '(') != (vp->type == FUNCTION)) {
				fprintf(stderr, "%s\n", string);
				fprintf(stderr,
					"%s: %s: Bad %s declaration: %s\n",
					progname, fname,
					vp->type == FUNCTION ?
					"function" : "variable",
					name);
				quit(1);
			}
			scompile(string, fname, 0);
			vp->v.dfn = savestr(string);
			break;
		case STRING:
			if (*s++ != '=') {
				fprintf(stderr, "%s\n", string);
				fprintf(stderr, "%s: %s: Missing '='\n",
						progname, fname);
				quit(1);
			}
			vp->v.s = savestr(s);
			break;
		case DATA:
			if (*s++ != '=') {
				fprintf(stderr, "%s\n", string);
				fprintf(stderr, "%s: %s: Missing '='\n",
						progname, fname);
				quit(1);
			}
			if (!*s) {
				loaddata(fname, fp, &vp->v.d);
			} else if (*s == '!') {
				if ((fp2 = popen(s+1, "r")) == NULL) {
					fprintf(stderr, "%s\n", string);
					fprintf(stderr,
					"%s: %s: Cannot execute: %s\n",
							progname, fname, s+1);
					quit(1);
				}
				loaddata(s, fp2, &vp->v.d);
				pclose(fp2);
			} else {
				if ((fp2 = fopen(s, "r")) == NULL) {
				    fprintf(stderr, "%s\n", string);
				    fprintf(stderr,
					    "%s: %s: Data file not found: %s\n",
					    progname, fname, s);
				    quit(1);
				}
				loaddata(s, fp2, &vp->v.d);
				fclose(fp2);
			}
			break;
		}
		vp->flags |= DEFINED;
	} else
		setivar(name, fname, string);		/* intermediate */
}
Beispiel #17
0
void Editor::formatLine( int ln ){
	if( ln<0 || ln>=editCtrl.GetLineCount() ) return;

	lineToFmt=-1;
	int pos=editCtrl.LineIndex( ln );
	string tline=getLine( ln );
	string line=tolower( tline );

	int *cf=0;
	string rep;
	for( int k=0;k<line.size(); ){
		rep.resize(0);
		int *pf=cf;
		int from=k,c=line[k],sz=line.size();
		if( !isgraph( c ) ){
			for( ++k;k<sz && !isgraph(line[k]);++k ){}
		}else if( !isfmt( c,k+1<sz?line[k+1]:0 ) ){
			for( ++k;k<sz && !isfmt(line[k],k+1<sz?line[k+1]:0);++k ){}
			cf=&prefs.rgb_default;
		}else if( c==';' ){					//comment?
			k=sz;
			cf=&prefs.rgb_comment;
		}else if( c=='\"' ){		//string const?
			for( ++k;k<sz && line[k]!='\"';++k ){}
			if( k<sz ) ++k;
			cf=&prefs.rgb_string;
		}else if( isalpha( c ) ){		//ident?
			for( ++k;k<sz && isid(line[k]);++k ){}
			cf=&prefs.rgb_ident;pf=0;
			if( selStart<=pos+from || selStart>pos+k ){
				map<string,string>::iterator it=keyWordMap.find( line.substr( from,k-from ) );
				if( it!=keyWordMap.end() ){
					rep=it->second;cf=&prefs.rgb_keyword;
				}
			}else lineToFmt=ln;
		}else if( c=='$' && k+1<sz && isxdigit(line[k+1]) ){
			for( ++k;k<sz && isxdigit(line[k]);++k ){}
			cf=&prefs.rgb_digit;
		}else if( isdigit( c ) ){	//numeric const?
			for( ++k;k<sz && isdigit(line[k]);++k ){}
			cf=&prefs.rgb_digit;
		}
		if( cf!=pf ) setFormat( pos+from,pos+k,*cf,rep );
	}
	if( line[0]=='f' && line.find( "function" )==0 ){
		for( int k=8;k<line.size();++k ){
			if( isalpha( line[k] ) ){
				int start=k;
				for( ++k;k<line.size() && isid(line[k]);++k ){}
				funcList.insert( ln,tline.substr( start,k-start ) );
				break;
			}
		}
	}else if( line[0]=='t' && line.find( "type" )==0 ){
		for( int k=4;k<line.size();++k ){
			if( isalpha( line[k] ) ){
				int start=k;
				for( ++k;k<line.size() && isid(line[k]);++k ){}
				typeList.insert( ln,tline.substr( start,k-start ) );
				break;
			}
		}
	}else if( line[0]=='.' ){
		for( int k=1;k<line.size();++k ){
			if( isalpha( line[k] ) ){
				int start=k;
				for( ++k;k<line.size() && isid(line[k]);++k ){}
				labsList.insert( ln,tline.substr( start,k-start ) );
				break;
			}
		}
	}
}
Beispiel #18
0
Datei: lex.c Projekt: jgshort/oo
oo_token *lex(FILE *fp, size_t sz) {
  size_t l;
  char *source = malloc(sz);
  oo_token *head = NULL, *curr = NULL;

  if(!source) goto err1;

  if(fseek(fp, 0L, SEEK_SET) != 0) goto err0;
  l = fread(source, sizeof(char), sz, fp);

  source[++l] = 0;
  char *cp = source;

  oo_floc empty = { .line = 0, .column = 0, .offset = 0};
  curr = head = alloc_token(oot_START, empty, 0, NULL);
  oo_floc loc = { .line = 1, .column = 1, .offset = -1 };
  oo_states state = oos_start, prev = state;
  
  uint32_t end_offset = 0;
  oo_floc block;
  do {
    char a = *cp;
    oo_tokens token = oot_UNKNOWN;

    step(&state, &cp, &loc);
    if(state == oos_err) goto syn;
   
    if (state == oos_str || state == oos_ident || state == oos_num) {
      block.line = loc.line;
      block.column = loc.column;
      block.offset = loc.offset;
    }
    
    int end_of_str = (state == oos_eo_str || state == oos_eo_id || state == oos_eo_num);
    if (end_of_str) {
      /* id, num & str */
      end_offset = loc.offset;
      int t = -1;

      if (state == oos_eo_id)   t = oot_IDENT;
      if (state == oos_eo_str)  t = oot_STR;
      if (state == oos_eo_num)  t = oot_NUM;

      if (t == oot_IDENT || t == oot_STR || t == oot_NUM) { 
        curr = alloc_token(t, block, end_offset - block.offset, curr);
      }
      if(state == oos_eo_id || state == oos_eo_num) {
        cp--;
        loc.offset--;
      }
      end_offset = 0;
    } else {
      /* sym */
      if (state == oos_sym) {
        char c = *(source + (loc.offset));
        token = oo_tokens_from_char(c); 
      }

      if(token != oot_UNKNOWN) {
        curr = alloc_token(token, loc, 1, curr);
      }
    }

syn:
    printf("o: %d, s -> %d, s_s = '%s' (%d)", (int)loc.offset, (int)state, oo_state_to_string(state), (int)a);
    if(isalpha(a) || isdigit(a) || issym(a)) {
      printf(", '%c'", a);
    }
    printf("\n");

    if(state == oos_err) {
      if(prev == oos_in_str) {
        printf("Syntax error, unterminated string constant, line %d column %d\n", block.line, block.column - 1);
      }

      /* TODO: Add oot_ERR token */
      curr = alloc_token(oot_EOF, loc, 1, curr);
      return head;
    }

    prev = state; 
 } while(state != oos_eof);

 if(state == oos_eof) {
   curr = alloc_token(oot_EOF, loc, 0, curr);
 }

err0:
  if(source) free(source), source = NULL;

err1:
  return head;
}

static void step(oo_states *state, char **cp, oo_floc *loc) {
  int c = **cp, k = 0;
  int i = -1; /* unknown */

  if(c != 0 && *(*cp+1) != 0) k = *(*cp +1);
  
  i = isspace(c)  ? 0 : i; /* ws */
  i = c == '\n'   ? 1 : i; /* new line */
  i = issym(c)    ? 2 : i; /* sym */
  i = isdigit(c)  ? 3 : i; /* numeric */
  i = isid(c)     ? 4 : i; /* id */
  i = c == '"'    ? 5 : i; /* str */
  i = isesc(c, k) ? 6 : i; /* escape */
  i = c == 0      ? 7 : i; /* eof */
 
  if(i == -1) printf("---> '%c'\n", c); 
  
  oo_branch *b = &table[*state][i];
  *state = b->state;
  if(b->advance) {
    if(b->state == oos_nl) {
      loc->line++;
      loc->column = 0;
    }

    loc->column++;
    loc->offset++;
    (*cp)++;
  }
}

static oo_tokens oo_tokens_from_char(int t) {
  if (t == '~') return oot_TILDE;
  if (t == '`') return oot_GACCENT;
  
  if (t == '!') return oot_BANG;
  if (t == '@') return oot_AT;
  if (t == '#') return oot_POUND;
  if (t == '$') return oot_DOLLAR;
  if (t == '%') return oot_PERCENT;
  if (t == '^') return oot_EXP;
  if (t == '&') return oot_AND;
  if (t == '*') return oot_STAR;
  if (t == '(') return oot_LPAREN;
  if (t == ')') return oot_RPAREN;
  if (t == '-') return oot_MINUS;
  if (t == '=') return oot_EQUAL;
  if (t == '_') return oot_UNDER;
  if (t == '+') return oot_PLUS;

  if (t == '[') return oot_LBRACKET;
  if (t == ']') return oot_RBRACKET;
  if (t == '\\') return oot_BSLASH;
  if (t == '{') return oot_LBRACE;
  if (t == '}') return oot_RBRACE;
  if (t == '|') return oot_BAR;

  if (t == ';') return oot_SEMI;
  if (t == '\'') return oot_SQUOTE;
  if (t == ':') return oot_COLON;
  if (t == '"') return oot_DQUOTE;

  if (t == ',') return oot_COMMA;
  if (t == '.') return oot_DOT;
  if (t == '/') return oot_FSLASH;
  if (t == '<') return oot_LT;
  if (t == '>') return oot_GT;
  if (t == '?') return oot_WHAT;

  return oot_UNKNOWN;
}

char *string_from_oo_tokens(oo_tokens t) {
  if (t == oot_START) return "oot_START";

  if (t == '~') return "oot_TILDE";
  if (t == '`') return "oot_GACCENT";
  
  if (t == '!') return "oot_BANG";
  if (t == '@') return "oot_AT";
  if (t == '#') return "oot_POUND";
  if (t == '$') return "oot_DOLLAR";
  if (t == '%') return "oot_PERCENT";
  if (t == '^') return "oot_EXP";
  if (t == '&') return "oot_AND";
  if (t == '*') return "oot_STAR";
  if (t == '(') return "oot_LPAREN";
  if (t == ')') return "oot_RPAREN";
  if (t == '-') return "oot_MINUS";
  if (t == '=') return "oot_EQUAL";
  if (t == '_') return "oot_UNDER";
  if (t == '+') return "oot_PLUS";

  if (t == '[') return "oot_LBRACKET";
  if (t == ']') return "oot_RBRACKET";
  if (t == '\\') return "oot_BSLASH";
  if (t == '{') return "oot_LBRACE";
  if (t == '}') return "oot_RBRACE";
  if (t == '|') return "oot_BAR";

  if (t == ';') return "oot_SEMI";
  if (t == '\'') return "oot_SQUOTE";
  if (t == ':') return "oot_COLON";
  if (t == '"') return "oot_DQUOTE";

  if (t == ',') return "oot_COMMA";
  if (t == '.') return "oot_DOT";
  if (t == '/') return "oot_FSLASH";
  if (t == '<') return "oot_LT";
  if (t == '>') return "oot_GT";
  if (t == '?') return "oot_WHAT";

  if (t == oot_IDENT) return "oot_IDENT";
  if (t == oot_NUM) return "oot_NUM";
  if (t == oot_STR) return "oot_STR";
  if (t == oot_EOF) return "oot_EOF";

  return "oot_UNKNOWN";
}

static char *oo_state_to_string(oo_states state) {
  if (state == oos_start) return "oos_start";
  if (state == oos_ws) return "oos_ws";
  if (state == oos_nl) return "oos_nl";

  if (state == oos_sym) return "oos_sym";

  if (state == oos_num) return "oos_num";
  if (state == oos_ident) return "oos_ident";

  if (state == oos_str) return "oos_str";
  if (state == oos_esc) return "oos_esc";

  if (state == oos_in_str) return "oos_in_str";
  if (state == oos_in_id) return "oos_in_id";
  if (state == oos_in_num) return "oos_in_num";

  if (state == oos_eo_str) return "oos_eo_str";
  if (state == oos_eo_id) return "oos_eo_id";
  if (state == oos_eo_num) return "oos_eo_num";

  if (state == oos_err) return "oos_err";

  if (state == oos_eof) return "oos_eof";
 
  return "undefined";
}

static int issym(int c) {
  return 
       c == '[' || c == ']' || c == '\\' 
    || c == '{' || c == '}' || c == '|'
    
    || c == ';' || c == '\''|| c == ':' || c == '"'
    
    || c == ',' || c == '.' || c == '/'
    || c == '<' || c == '>' || c == '?'

    || c == '~' || c == '`' || c == '!' || c == '@' || c == '#' || c == '$'
    || c == '%' || c == '^' || c == '&' || c == '*' || c == '(' || c == ')'
    
    || c == '-' || c == '_' || c == '=' || c == '+'
    ;  
}

static int isid(int c) {
  return isalpha(c) || c == '_';
}

static int isesc(int c, int k) {
  if(c == 0) return 0;
  if(k == 0) return 0;

  if(c == '\\') {
    if (k == '"') return 1;
    if (k == '\\') return 1;
    if (k == 'r') return 1;
    if (k == 'n') return 1;
  }

  return 0;
}