/* Copyright (c) 2003, Steve Dekorte All rights reserved. See _BSDLicense.txt. Aug 2004 - removed {} from op chars - changed identifier to stop after 1 colon */ #include "IoLexer.h" #include #include #include #include //#define LEXER_DEBUG //#define LEXER_DEBUG_TOKENS #define TEST_INLINE inline static IoToken *IoLexer_currentToken(IoLexer *self) { return List_top(self->tokenStream); } IoLexer *IoLexer_new(void) { IoLexer *self = (IoLexer *)calloc(1, sizeof(IoLexer)); self->s = (char *)calloc(1, 1); self->posStack = Stack_new(); self->tokenStack = Stack_new(); self->tokenStream = List_new(); self->charLineIndex = List_new(); return self; } void IoLexer_free(IoLexer *self) { IoLexer_clear(self); free(self->s); Stack_free(self->posStack); Stack_free(self->tokenStack); List_free(self->tokenStream); List_free(self->charLineIndex); if(self->errorDescription) free(self->errorDescription); free(self); } char *IoLexer_errorDescription(IoLexer *self) { IoToken *et = IoLexer_errorToken(self); if (!self->errorDescription) { self->errorDescription = calloc(1, 1024); } if (et) { sprintf(self->errorDescription, "\"%s\" on line %i character %i", et->error, IoToken_lineNumber(et), IoToken_charNumber(et)); } return self->errorDescription; } void IoLexer_buildLineIndex(IoLexer *self) { char *s = self->s; List_removeAll(self->charLineIndex); List_append_(self->charLineIndex, s); while (*s) { if (*s == '\n') { List_append_(self->charLineIndex, s); } s ++; } List_append_(self->charLineIndex, s); self->lineHint = 0; } // next/prev character ------------------------ #define UTF8_SEQLEN(c) ( \ (c) < 0x80 ? 1 : \ (c) < 0xe0 ? 2 : \ (c) < 0xf0 ? 3 : \ (c) < 0xf8 ? 4 : \ (c) < 0xfc ? 5 : \ (c) < 0xfe ? 6 : 1 \ ) #define INVALID_CHAR 0xfffe static uchar_t _IoLexer_DecodeUTF8(const unsigned char *s) { if (*s < 0x80) return *s; else if (*s < 0xc2) return INVALID_CHAR; else if (*s < 0xe0) { if (!((s[1] ^ 0x80) < 0x40)) return INVALID_CHAR; return ((uchar_t)(s[0] & 0x1f) << 6) | (uchar_t)(s[1] ^ 0x80); } else if (*s < 0xf0) { if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[0] >= 0xe1 || s[1] >= 0xa0))) return INVALID_CHAR; return ((uchar_t)(s[0] & 0x0f) << 12) | ((uchar_t)(s[1] ^ 0x80) << 6) | (uchar_t)(s[2] ^ 0x80); } else if (*s < 0xf8) { if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[0] >= 0xf1 || s[1] >= 0x90))) return INVALID_CHAR; return ((uchar_t)(s[0] & 0x07) << 18) | ((uchar_t)(s[1] ^ 0x80) << 12) | ((uchar_t)(s[2] ^ 0x80) << 6) | (uchar_t)(s[3] ^ 0x80); } else if (*s < 0xfc) { if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40 && (s[0] >= 0xf9 || s[1] >= 0x88))) return INVALID_CHAR; return ((uchar_t)(s[0] & 0x03) << 24) | ((uchar_t)(s[1] ^ 0x80) << 18) | ((uchar_t)(s[2] ^ 0x80) << 12) | ((uchar_t)(s[3] ^ 0x80) << 6) | (uchar_t)(s[4] ^ 0x80); } else if (*s < 0xfe) { if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40 && (s[5] ^ 0x80) < 0x40 && (s[0] >= 0xfd || s[1] >= 0x84))) return INVALID_CHAR; return ((uchar_t)(s[0] & 0x01) << 30) | ((uchar_t)(s[1] ^ 0x80) << 24) | ((uchar_t)(s[2] ^ 0x80) << 18) | ((uchar_t)(s[3] ^ 0x80) << 12) | ((uchar_t)(s[4] ^ 0x80) << 6) | (uchar_t)(s[5] ^ 0x80); } else return INVALID_CHAR; } TEST_INLINE uchar_t IoLexer_nextChar(IoLexer *self) { unsigned char c = (unsigned char) * (self->current); int seqlen, i; uchar_t uch; if (c == 0) { return 0; } else if (c < 0x80) { self->current++; return c; } seqlen = UTF8_SEQLEN(c); for (i = 0; i < seqlen; i++) { if (self->current[i] == 0) { // XXX: invalid or incomplete sequence return 0; } } uch = _IoLexer_DecodeUTF8((unsigned char*)self->current); if (uch == INVALID_CHAR) { return 0; } self->current += seqlen; return uch; } TEST_INLINE uchar_t IoLexer_prevChar(IoLexer *self) { uchar_t uch; int len; for (len = 1; len <= 6 && self->current - len > self->s; len++) { unsigned char c = *(unsigned char *)(self->current - len); if (c < 0x80 || c >= 0xc2) break; } self->current -= len; uch = _IoLexer_DecodeUTF8((unsigned char*)self->current); if (uch == INVALID_CHAR) return 0; return uch; } TEST_INLINE char *IoLexer_current(IoLexer *self) { return self->current; } TEST_INLINE int IoLexer_onNULL(IoLexer *self) { return (*(self->current) == 0); } // ------------------------------------------ size_t IoLexer_currentLineNumberOld(IoLexer *self) { size_t lineNumber = 1; char *s = self->s; while (s < self->current) { if (*s == '\n') { lineNumber ++; } s ++; } return lineNumber; } TEST_INLINE size_t IoLexer_currentLineNumber(IoLexer *self) { // this should be even faster than a binary search // since almost all results are very close to the last List *index = self->charLineIndex; size_t line = self->lineHint; size_t numLines = List_size(index); void *current = (void *)self->current; if (current < List_at_(index, line)) { // walk down lines until char is bigger than one while (line > 0 && !(current > List_at_(index, line))) { line --; } line ++; } else { // walk up lines until char is less than or equal to one while (line < numLines && !(current <= List_at_(index, line))) { line ++; } } self->lineHint = line; /* { size_t realLine = IoLexer_currentLineNumberOld(self); if (line != realLine) { printf("mismatch on currentLine %i != %i\n", (int)line, (int)realLine); } } */ return line; } void IoLexer_clear(IoLexer *self) { LIST_FOREACH(self->tokenStream, i, t, IoToken_free((IoToken *)t) ); List_removeAll(self->tokenStream); Stack_clear(self->posStack); Stack_clear(self->tokenStack); self->current = self->s; self->resultIndex = 0; self->maxChar = 0; self->errorToken = NULL; } IoToken *IoLexer_errorToken(IoLexer *self) { return self->errorToken; } // lexing ------------------------------------- void IoLexer_string_(IoLexer *self, const char *string) { self->s = strcpy((char *)realloc(self->s, strlen(string) + 1), string); self->current = self->s; IoLexer_buildLineIndex(self); } void IoLexer_printLast_(IoLexer *self, int max) { char *s = self->s + self->maxChar; int i; for (i = 0; i < max && s[i]; i ++) { putchar(s[i]); } } // --- token and character position stacks --- char *IoLexer_lastPos(IoLexer *self) { return Stack_top(self->posStack); } TEST_INLINE void IoLexer_pushPos(IoLexer *self) { ptrdiff_t index = self->current - self->s; if (index > (ptrdiff_t)self->maxChar) { self->maxChar = index; } Stack_push_(self->tokenStack, (void *)(ptrdiff_t)(List_size(self->tokenStream) - 1)); Stack_push_(self->posStack, self->current); #ifdef LEXER_DEBUG printf("push: "); IoLexer_print(self); #endif } TEST_INLINE void IoLexer_popPos(IoLexer *self) { Stack_pop(self->tokenStack); Stack_pop(self->posStack); #ifdef LEXER_DEBUG printf("pop: "); IoLexer_print(self); #endif } TEST_INLINE void IoLexer_popPosBack(IoLexer *self) { ptrdiff_t i = (ptrdiff_t)Stack_pop(self->tokenStack); ptrdiff_t topIndex = (ptrdiff_t)Stack_top(self->tokenStack); if (i > -1) { List_setSize_(self->tokenStream, i + 1); if (i != topIndex) // ok to free token { IoToken *parent = IoLexer_currentToken(self); if (parent) { IoToken_nextToken_(parent, NULL); } } } self->current = Stack_pop(self->posStack); #ifdef LEXER_DEBUG printf("back: "); IoLexer_print(self); #endif } // ------------------------------------------ int IoLexer_lex(IoLexer *self) { IoLexer_clear(self); IoLexer_pushPos(self); IoLexer_messageChain(self); if (*(self->current)) { //printf("Lexing error after: "); //IoLexer_printLast_(self, 30); //printf("\n"); if (!self->errorToken) { if (List_size(self->tokenStream)) { self->errorToken = IoLexer_currentToken(self); } else { self->errorToken = IoLexer_addTokenString_length_type_(self, self->current, 30, NO_TOKEN); } IoToken_error_(self->errorToken, "Syntax error near this location"); } return -1; } return 0; } // getting results -------------------------------- IoToken *IoLexer_top(IoLexer *self) { return List_at_(self->tokenStream, self->resultIndex); } IoTokenType IoLexer_topType(IoLexer *self) { if (!IoLexer_top(self)) { return 0; } return IoLexer_top(self)->type; } IoToken *IoLexer_pop(IoLexer *self) { IoToken *t = IoLexer_top(self); self->resultIndex ++; return t; } // stack management -------------------------------- void IoLexer_print(IoLexer *self) { IoToken *first = List_first(self->tokenStream); if (first) { IoToken_print(first); } printf("\n"); } void IoLexer_printTokens(IoLexer *self) { int i; for (i = 0; i < List_size(self->tokenStream); i ++) { IoToken *t = List_at_(self->tokenStream, i); printf("'%s'", t->name); printf(" %s ", IoToken_typeName(t)); if (i < List_size(self->tokenStream) - 1) { printf(", "); } } printf("\n"); } // grabbing --------------------------------------------- int IoLexer_grabLength(IoLexer *self) { char *s1 = IoLexer_lastPos(self); char *s2 = IoLexer_current(self); return s2 - s1; } void IoLexer_grabTokenType_(IoLexer *self, IoTokenType type) { char *s1 = IoLexer_lastPos(self); char *s2 = IoLexer_current(self); size_t len = (s2 - s1); if (!len) { printf("IoLexer fatal error: empty token\n"); exit(1); } IoLexer_addTokenString_length_type_(self, s1, len, type); } IoToken *IoLexer_addTokenString_length_type_(IoLexer *self, const char *s1, size_t len, IoTokenType type) { IoToken *top = IoLexer_currentToken(self); IoToken *t = IoToken_new(); t->lineNumber = IoLexer_currentLineNumber(self); //t->charNumber = (int)(s1 - self->s); t->charNumber = (int)(self->current - self->s); if (t->charNumber < 0) { printf("bad t->charNumber = %i\n", t->charNumber); } IoToken_name_length_(t, s1, len); IoToken_type_(t, type); if (top) { IoToken_nextToken_(top, t); } List_push_(self->tokenStream, t); #ifdef LEXER_DEBUG_TOKENS printf("token '%s' %s\n", t->name, IoToken_typeName(t)); #endif return t; } // reading ------------------------------------ void IoLexer_messageChain(IoLexer *self) { do { while ( IoLexer_readTerminator(self) || IoLexer_readSeparator(self) || IoLexer_readComment(self)) {} } while ( IoLexer_readMessage(self)); } // message ------------------------------- static void IoLexer_readMessage_error(IoLexer *self, const char *name) { IoLexer_popPosBack(self); self->errorToken = IoLexer_currentToken(self); IoToken_error_(self->errorToken, name); } int IoLexer_readTokenChars_type_(IoLexer *self, const char *chars, IoTokenType type) { while (*chars) { if (IoLexer_readTokenChar_type_(self, *chars, type)) return 1; chars ++; } return 0; } const char *IoLexer_nameForGroupChar_(IoLexer *self, char groupChar) { switch (groupChar) { case '(': return ""; case '[': return "squareBrackets"; case '{': return "curlyBrackets"; } printf("IoLexer: fatal error - invalid group char %c\n", groupChar); exit(1); } static char *specialChars = ":._"; int IoLexer_readMessage(IoLexer *self) { char foundSymbol; IoLexer_pushPos(self); IoLexer_readPadding(self); foundSymbol = IoLexer_readSymbol(self); { char groupChar; while (IoLexer_readSeparator(self) || IoLexer_readComment(self)) {} groupChar = *IoLexer_current(self); if (groupChar && (strchr("[{", groupChar) || (!foundSymbol && groupChar == '('))) { char *groupName = (char *)IoLexer_nameForGroupChar_(self, groupChar); IoLexer_addTokenString_length_type_(self, groupName, strlen(groupName), IDENTIFIER_TOKEN); } if (IoLexer_readTokenChars_type_(self, "([{", OPENPAREN_TOKEN)) { IoLexer_readPadding(self); do { IoTokenType type = IoLexer_currentToken(self)->type; IoLexer_readPadding(self); // Empty argument: (... ,) if (COMMA_TOKEN == type) { char c = *IoLexer_current(self); if (',' == c || strchr(")]}", c)) { IoLexer_readMessage_error(self, "missing argument in argument list"); return 0; } } if (groupChar == '[') specialChars = "._"; IoLexer_messageChain(self); if (groupChar == '[') specialChars = ":._"; IoLexer_readPadding(self); } while (IoLexer_readTokenChar_type_(self, ',', COMMA_TOKEN)); if (!IoLexer_readTokenChars_type_(self, ")]}", CLOSEPAREN_TOKEN)) { /* char c = *IoLexer_current(self); if (strchr("([{", c)) { IoLexer_readMessage_error(self, "expected a message but instead found a open group character"); } else { IoLexer_readMessage_error(self, "missing closing group character for argument list"); } */ if (groupChar == '(') { IoLexer_readMessage_error(self, "unmatched ()s"); } else if (groupChar == '[') { IoLexer_readMessage_error(self, "unmatched []s"); } else if (groupChar == '{') { IoLexer_readMessage_error(self, "unmatched {}s"); } //printf("Token %p error: %s - %s\n", t, t->error, IoToken_error(t)); return 0; } IoLexer_popPos(self); return 1; } if (foundSymbol) { IoLexer_popPos(self); return 1; } } IoLexer_popPosBack(self); return 0; } int IoLexer_readPadding(IoLexer *self) { int r = 0; while (IoLexer_readWhitespace(self) || IoLexer_readComment(self)) { r = 1; } return r; } // symbols ------------------------------------------ int IoLexer_readSymbol(IoLexer *self) { if ( IoLexer_readNumber(self) || IoLexer_readOperator(self) || IoLexer_readIdentifier(self) || IoLexer_readQuote(self)) return 1; return 0; } int IoLexer_readIdentifier(IoLexer *self) { IoLexer_pushPos(self); while ( IoLexer_readLetter(self) || IoLexer_readDigit(self) || IoLexer_readSpecialChar(self)) {} if (IoLexer_grabLength(self)) { // avoid grabing : on last character if followed by = char *current = IoLexer_current(self); if (*(current - 1) == ':' && *current == '=') { IoLexer_prevChar(self); } IoLexer_grabTokenType_(self, IDENTIFIER_TOKEN); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } int IoLexer_readOperator(IoLexer *self) { uchar_t c; IoLexer_pushPos(self); // ok if first character is a colon c = IoLexer_nextChar(self); //printf("IoLexer_nextChar(self) = %c %i\n", c, c); if (c == 0) { IoLexer_popPosBack(self); return 0; } else { IoLexer_prevChar(self); } /* if (c != ':') { IoLexer_prevChar(self); } */ while (IoLexer_readOpChar(self)) { } if (IoLexer_grabLength(self)) { IoLexer_grabTokenType_(self, IDENTIFIER_TOKEN); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } // comments ------------------------------------------ int IoLexer_readComment(IoLexer *self) { return (IoLexer_readSlashStarComment(self) || IoLexer_readSlashSlashComment(self) || IoLexer_readPoundComment(self)); } int IoLexer_readSlashStarComment(IoLexer *self) { IoLexer_pushPos(self); if (IoLexer_readString_(self, "/*")) { unsigned int nesting = 1; while (nesting > 0) { if (IoLexer_readString_(self, "/*")) { IoLexer_nextChar(self); nesting++; } else if (IoLexer_readString_(self, "*/")) { // otherwise we end up trimming the last char if (nesting > 1) IoLexer_nextChar(self); nesting--; } else IoLexer_nextChar(self); } IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } int IoLexer_readSlashSlashComment(IoLexer *self) { IoLexer_pushPos(self); if (IoLexer_nextChar(self) == '/') { if (IoLexer_nextChar(self) == '/') { while (IoLexer_readNonReturn(self)) { } //IoLexer_grabTokenType_(self, COMMENT_TOKEN); IoLexer_popPos(self); return 1; } } IoLexer_popPosBack(self); return 0; } int IoLexer_readPoundComment(IoLexer *self) { IoLexer_pushPos(self); if (IoLexer_nextChar(self) == '#') { while (IoLexer_readNonReturn(self)) { } //IoLexer_grabTokenType_(self, COMMENT_TOKEN); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } // quotes ----------------------------------------- int IoLexer_readQuote(IoLexer *self) { return (IoLexer_readTriQuote(self) || IoLexer_readMonoQuote(self)); } int IoLexer_readMonoQuote(IoLexer *self) { int mbskip = 0; // multi-byte character length IoLexer_pushPos(self); if (IoLexer_nextChar(self) == '"') { for (;;) { uchar_t c = IoLexer_nextChar(self); if (mbskip <= 0 && ismbchar(c)) { mbskip = mbcharlen(c); } if (mbskip-- > 0) { continue; } if (c == '"') { break; } if (c == '\\') { IoLexer_nextChar(self); continue; } if (c == 0) { self->errorToken = IoLexer_currentToken(self); if (self->errorToken) { IoToken_error_(self->errorToken, "unterminated quote"); } IoLexer_popPosBack(self); return 0; } } IoLexer_grabTokenType_(self, MONOQUOTE_TOKEN); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } int IoLexer_readTriQuote(IoLexer *self) { IoLexer_pushPos(self); if (IoLexer_readString_(self, "\"\"\"")) { while (!IoLexer_readString_(self, "\"\"\"")) { uchar_t c = IoLexer_nextChar(self); if (c == 0) { IoLexer_popPosBack(self); return 0; } } IoLexer_grabTokenType_(self, TRIQUOTE_TOKEN); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } // helpers ---------------------------- int IoLexer_readTokenChar_type_(IoLexer *self, char c, IoTokenType type) { IoLexer_pushPos(self); if (IoLexer_readChar_(self, c)) { IoLexer_grabTokenType_(self, type); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } int IoLexer_readTokenString_(IoLexer *self, const char *s) { IoLexer_pushPos(self); if (IoLexer_readString_(self, s)) { IoLexer_grabTokenType_(self, IDENTIFIER_TOKEN); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } int IoLexer_readString_(IoLexer *self, const char *s) { int len = strlen(s); if (IoLexer_onNULL(self)) { return 0; } if (strncmp(self->current, s, len) == 0) { self->current += len; return 1; } return 0; } TEST_INLINE int IoLexer_readCharIn_(IoLexer *self, const char *s) { if (!IoLexer_onNULL(self)) { uchar_t c = IoLexer_nextChar(self); if (c < 0x80 && strchr(s, c)) { return 1; } IoLexer_prevChar(self); } return 0; } TEST_INLINE int IoLexer_readCharInRange_(IoLexer *self, uchar_t first, uchar_t last) { if (!IoLexer_onNULL(self)) { uchar_t c = IoLexer_nextChar(self); if (c >= first && c <= last) { return 1; } IoLexer_prevChar(self); } return 0; } int IoLexer_readChar_(IoLexer *self, char c) { if (!IoLexer_onNULL(self)) { uchar_t nc = IoLexer_nextChar(self); if (nc && nc == c) { return 1; } IoLexer_prevChar(self); } return 0; } int IoLexer_readCharAnyCase_(IoLexer *self, char c) { if (!IoLexer_onNULL(self)) { uchar_t nc = IoLexer_nextChar(self); if (nc && tolower(nc) == tolower(c)) { return 1; } IoLexer_prevChar(self); } return 0; } int IoLexer_readNonASCIIChar_(IoLexer *self) { if (!IoLexer_onNULL(self)) { uchar_t nc = IoLexer_nextChar(self); if (nc >= 0x80) return 1; IoLexer_prevChar(self); } return 0; } int IoLexer_readNonReturn(IoLexer *self) { if (IoLexer_onNULL(self)) return 0; if (IoLexer_nextChar(self) != '\n') return 1; IoLexer_prevChar(self); return 0; } int IoLexer_readNonQuote(IoLexer *self) { if (IoLexer_onNULL(self)) return 0; if (IoLexer_nextChar(self) != '"') return 1; IoLexer_prevChar(self); return 0; } // character definitions ---------------------------- int IoLexer_readCharacters(IoLexer *self) { int read = 0; while (IoLexer_readCharacter(self)) { read = 1; } return read; } int IoLexer_readCharacter(IoLexer *self) { return ( IoLexer_readLetter(self) || IoLexer_readDigit(self) || IoLexer_readSpecialChar(self) || IoLexer_readOpChar(self) ); } int IoLexer_readOpChar(IoLexer *self) { return IoLexer_readCharIn_(self, ":'~!@$%^&*-+=|\\<>?/"); } int IoLexer_readSpecialChar(IoLexer *self) { return IoLexer_readCharIn_(self, specialChars); } int IoLexer_readDigit(IoLexer *self) { return IoLexer_readCharInRange_(self, '0', '9'); } int IoLexer_readLetter(IoLexer *self) { return IoLexer_readCharInRange_(self, 'A', 'Z') || IoLexer_readCharInRange_(self, 'a', 'z') || IoLexer_readNonASCIIChar_(self); } // terminator ------------------------------- int IoLexer_readTerminator(IoLexer *self) { int terminated = 0; IoLexer_pushPos(self); IoLexer_readSeparator(self); while (IoLexer_readTerminatorChar(self)) { terminated = 1; IoLexer_readSeparator(self); } if (terminated) { IoToken *top = IoLexer_currentToken(self); // avoid double terminators if (top && IoToken_type(top) == TERMINATOR_TOKEN) { return 1; } IoLexer_addTokenString_length_type_(self, ";", 1, TERMINATOR_TOKEN); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } int IoLexer_readTerminatorChar(IoLexer *self) { return IoLexer_readCharIn_(self, ";\n"); } // separator -------------------------------- int IoLexer_readSeparator(IoLexer *self) { IoLexer_pushPos(self); while (IoLexer_readSeparatorChar(self)) { } if (IoLexer_grabLength(self)) { //IoLexer_grabTokenType_(self, SEPERATOR_TOKEN); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } int IoLexer_readSeparatorChar(IoLexer *self) { //return IoLexer_readCharIn_(self, " \f\r\t\v"); return IoLexer_readCharIn_(self, " \f\r\t\v") || (IoLexer_readCharIn_(self, "\\") && IoLexer_readCharIn_(self, "\n")); } // whitespace ----------------------------------- int IoLexer_readWhitespace(IoLexer *self) { IoLexer_pushPos(self); while (IoLexer_readWhitespaceChar(self)) { } if (IoLexer_grabLength(self)) { //IoLexer_grabTokenType_(self, WHITESPACE_TOKEN); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; } int IoLexer_readWhitespaceChar(IoLexer *self) { return IoLexer_readCharIn_(self, " \f\r\t\v\n"); } int IoLexer_readDigits(IoLexer *self) { int read = 0; IoLexer_pushPos(self); while (IoLexer_readDigit(self)) { read = 1; } if (!read) { IoLexer_popPosBack(self); return 0; } IoLexer_popPos(self); return read; } int IoLexer_readNumber(IoLexer *self) { return (IoLexer_readHexNumber(self) || IoLexer_readDecimal(self)); } int IoLexer_readExponent(IoLexer *self) { if (IoLexer_readCharAnyCase_(self, 'e')) { IoLexer_readChar_(self, '-'); if (!IoLexer_readDigits(self)) { return -1; } return 1; } return 0; } int IoLexer_readDecimalPlaces(IoLexer *self) { if (IoLexer_readChar_(self, '.')) { if (!IoLexer_readDigits(self)) { return -1; } return 1; } return 0; } int IoLexer_readDecimal(IoLexer *self) { IoLexer_pushPos(self); if (IoLexer_readDigits(self)) { if (IoLexer_readDecimalPlaces(self) == -1) { goto error; } } else { if (IoLexer_readDecimalPlaces(self) != 1) { goto error; } } if (IoLexer_readExponent(self) == -1) { goto error; } if (IoLexer_grabLength(self)) { IoLexer_grabTokenType_(self, NUMBER_TOKEN); IoLexer_popPos(self); return 1; } error: IoLexer_popPosBack(self); return 0; } int IoLexer_readHexNumber(IoLexer *self) { int read = 0; IoLexer_pushPos(self); if (IoLexer_readChar_(self, '0') && IoLexer_readCharAnyCase_(self, 'x')) { while (IoLexer_readDigits(self) || IoLexer_readCharacters(self)) { read ++; } } if (read && IoLexer_grabLength(self)) { IoLexer_grabTokenType_(self, HEXNUMBER_TOKEN); IoLexer_popPos(self); return 1; } IoLexer_popPosBack(self); return 0; }