123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- /*
- * token lex for finsh shell.
- *
- * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
- *
- * This file is part of RT-Thread (http://www.rt-thread.org)
- * Maintainer: bernard.xiong <bernard.xiong at gmail.com>
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Change Logs:
- * Date Author Notes
- * 2010-03-22 Bernard first version
- * 2013-04-03 Bernard strip more characters.
- */
- #include <finsh.h>
- #include <stdlib.h>
- #include "finsh_token.h"
- #include "finsh_error.h"
- #define is_alpha(ch) ((ch | 0x20) - 'a') < 26u
- #define is_digit(ch) ((ch) >= '0' && (ch) <= '9')
- #define is_xdigit(ch) (((ch) >= '0' && (ch) <= '9') || (((ch | 0x20) - 'a') < 6u))
- #define is_separator(ch) !(((ch) >= 'a' && (ch) <= 'z') \
- || ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= '0' && (ch) <= '9') || ((ch) == '_'))
- #define is_eof(self) (self)->eof
- struct name_table
- {
- char* name;
- enum finsh_token_type type;
- };
- /* keyword */
- static const struct name_table finsh_name_table[] =
- {
- {"void", finsh_token_type_void},
- {"char", finsh_token_type_char},
- {"short", finsh_token_type_short},
- {"int", finsh_token_type_int},
- {"long", finsh_token_type_long},
- {"unsigned", finsh_token_type_unsigned},
- {"NULL", finsh_token_type_value_null},
- {"null", finsh_token_type_value_null}
- };
- static char token_next_char(struct finsh_token* self);
- static void token_prev_char(struct finsh_token* self);
- static long token_spec_number(char* string, int length, int b);
- static void token_run(struct finsh_token* self);
- static int token_match_name(struct finsh_token* self, const char* str);
- static void token_proc_number(struct finsh_token* self);
- static u_char* token_proc_string(struct finsh_token* self);
- static void token_trim_space(struct finsh_token* self);
- static char token_proc_char(struct finsh_token* self);
- static int token_proc_escape(struct finsh_token* self);
- void finsh_token_init(struct finsh_token* self, u_char* line)
- {
- memset(self, 0, sizeof(struct finsh_token));
- self->line = line;
- }
- enum finsh_token_type finsh_token_token(struct finsh_token* self)
- {
- if ( self->replay ) self->replay = 0;
- else token_run(self);
- return (enum finsh_token_type)self->current_token;
- }
- void finsh_token_get_token(struct finsh_token* self, u_char* token)
- {
- strncpy((char*)token, (char*)self->string, FINSH_NAME_MAX);
- }
- int token_get_string(struct finsh_token* self, u_char* str)
- {
- unsigned char *p=str;
- char ch;
- ch = token_next_char(self);
- if (is_eof(self)) return -1;
- str[0] = '\0';
- if ( is_digit(ch) )/*the first character of identifier is not a digit.*/
- {
- token_prev_char(self);
- return -1;
- }
- while (!is_separator(ch) && !is_eof(self))
- {
- *p++ = ch;
- ch = token_next_char(self);
- }
- self->eof = 0;
- token_prev_char(self);
- *p = '\0';
- return 0;
- }
- /*
- get next character.
- */
- static char token_next_char(struct finsh_token* self)
- {
- if (self->eof) return '\0';
- if (self->position == (int)strlen((char*)self->line) || self->line[self->position] =='\n')
- {
- self->eof = 1;
- self->position = 0;
- return '\0';
- }
- return self->line[self->position++];
- }
- static void token_prev_char(struct finsh_token* self)
- {
- if ( self->eof ) return;
- if ( self->position == 0 ) return;
- else self->position--;
- }
- static void token_run(struct finsh_token* self)
- {
- char ch;
- token_trim_space(self); /* first trim space and tab. */
- token_get_string(self, &(self->string[0]));
- if ( is_eof(self) ) /*if it is eof, break;*/
- {
- self->current_token = finsh_token_type_eof;
- return ;
- }
- if (self->string[0] != '\0') /*It is a key word or a identifier.*/
- {
- if ( !token_match_name(self, (char*)self->string) )
- {
- self->current_token = finsh_token_type_identifier;
- }
- }
- else/*It is a operator character.*/
- {
- ch = token_next_char(self);
- switch ( ch )
- {
- case '(':
- self->current_token = finsh_token_type_left_paren;
- break;
- case ')':
- self->current_token = finsh_token_type_right_paren;
- break;
- case ',':
- self->current_token = finsh_token_type_comma;
- break;
- case ';':
- self->current_token = finsh_token_type_semicolon;
- break;
- case '&':
- self->current_token = finsh_token_type_and;
- break;
- case '*':
- self->current_token = finsh_token_type_mul;
- break;
- case '+':
- ch = token_next_char(self);
- if ( ch == '+' )
- {
- self->current_token = finsh_token_type_inc;
- }
- else
- {
- token_prev_char(self);
- self->current_token = finsh_token_type_add;
- }
- break;
- case '-':
- ch = token_next_char(self);
- if ( ch == '-' )
- {
- self->current_token = finsh_token_type_dec;
- }
- else
- {
- token_prev_char(self);
- self->current_token = finsh_token_type_sub;
- }
- break;
- case '/':
- ch = token_next_char(self);
- if (ch == '/')
- {
- /* line comments, set to end of file */
- self->current_token = finsh_token_type_eof;
- }
- else
- {
- token_prev_char(self);
- self->current_token = finsh_token_type_div;
- }
- break;
- case '<':
- ch = token_next_char(self);
- if ( ch == '<' )
- {
- self->current_token = finsh_token_type_shl;
- }
- else
- {
- token_prev_char(self);
- self->current_token = finsh_token_type_bad;
- }
- break;
- case '>':
- ch = token_next_char(self);
- if ( ch == '>' )
- {
- self->current_token = finsh_token_type_shr;
- }
- else
- {
- token_prev_char(self);
- self->current_token = finsh_token_type_bad;
- }
- break;
- case '|':
- self->current_token = finsh_token_type_or;
- break;
- case '%':
- self->current_token = finsh_token_type_mod;
- break;
- case '~':
- self->current_token = finsh_token_type_bitwise;
- break;
- case '^':
- self->current_token = finsh_token_type_xor;
- break;
- case '=':
- self->current_token = finsh_token_type_assign;
- break;
- case '\'':
- self->value.char_value = token_proc_char(self);
- self->current_token = finsh_token_type_value_char;
- break;
- case '"':
- token_proc_string(self);
- self->current_token = finsh_token_type_value_string;
- break;
- default:
- if ( is_digit(ch) )
- {
- token_prev_char(self);
- token_proc_number(self);
- break;
- }
- finsh_error_set(FINSH_ERROR_UNKNOWN_TOKEN);
- self->current_token = finsh_token_type_bad;
- break;
- }
- }
- }
- static int token_match_name(struct finsh_token* self, const char* str)
- {
- int i;
- for (i = 0; i < sizeof(finsh_name_table)/sizeof(struct name_table); i++)
- {
- if ( strcmp(finsh_name_table[i].name, str)==0 )
- {
- self->current_token = finsh_name_table[i].type;
- return 1;
- }
- }
- return 0;
- }
- static void token_trim_space(struct finsh_token* self)
- {
- char ch;
- while ( (ch = token_next_char(self)) ==' ' ||
- ch == '\t' ||
- ch == '\r');
- token_prev_char(self);
- }
- static char token_proc_char(struct finsh_token* self)
- {
- char ch;
- char buf[4], *p;
- p = buf;
- ch = token_next_char(self);
- if ( ch == '\\' )
- {
- ch = token_next_char(self);
- switch ( ch )
- {
- case 'n': ch = '\n'; break;
- case 't': ch = '\t'; break;
- case 'v': ch = '\v'; break;
- case 'b': ch = '\b'; break;
- case 'r': ch = '\r'; break;
- case '\\': ch = '\\'; break;
- case '\'': ch = '\''; break;
- default :
- while ( is_digit(ch) )/*for '\113' char*/
- {
- ch = token_next_char(self);
- *p++ = ch;
- }
- token_prev_char(self);
- *p = '\0';
- ch = atoi(p);
- break;
- }
- }
- if ( token_next_char(self) != '\'' )
- {
- token_prev_char(self);
- finsh_error_set(FINSH_ERROR_EXPECT_CHAR);
- return ch;
- }
- return ch;
- }
- static u_char* token_proc_string(struct finsh_token* self)
- {
- u_char* p;
- for ( p = &self->string[0]; p - &(self->string[0]) < FINSH_STRING_MAX; )
- {
- char ch = token_next_char(self);
- if ( is_eof(self) )
- {
- finsh_error_set(FINSH_ERROR_UNEXPECT_END);
- return NULL;;
- }
- if ( ch == '\\' )
- {
- ch = token_proc_escape(self);
- }
- else if ( ch == '"' )/*end of string.*/
- {
- *p = '\0';
- return self->string;
- }
- *p++ = ch;
- }
- return NULL;
- }
- static int token_proc_escape(struct finsh_token* self)
- {
- char ch;
- int result=0;
- ch = token_next_char(self);
- switch (ch)
- {
- case 'n':
- result = '\n';
- break;
- case 't':
- result = '\t';
- break;
- case 'v':
- result = '\v';
- break;
- case 'b':
- result = '\b';
- break;
- case 'r':
- result = '\r';
- break;
- case 'f':
- result = '\f';
- break;
- case 'a':
- result = '\007';
- break;
- case '"':
- result = '"';
- break;
- case 'x':
- case 'X':
- result = 0;
- ch = token_next_char(self);
- while (is_xdigit(ch))
- {
- result = result * 16 + ((ch < 'A') ? (ch - '0') : (ch | 0x20) - 'a' + 10);
- ch = token_next_char(self);
- }
- token_prev_char(self);
- break;
- default:
- if ( (ch - '0') < 8u)
- {
- result = 0;
- while ( (ch - '0') < 8u )
- {
- result = result*8 + ch - '0';
- ch = token_next_char(self);
- }
- token_prev_char(self);
- }
- break;
- }
- return result;
- }
- /*
- (0|0x|0X|0b|0B)number+(l|L)
- */
- static void token_proc_number(struct finsh_token* self)
- {
- char ch;
- char *p, buf[128];
- long value;
- value = 0;
- p = buf;
- ch = token_next_char(self);
- if ( ch == '0' )
- {
- int b;
- ch = token_next_char(self);
- if ( ch == 'x' || ch == 'X' )/*it's a hex number*/
- {
- b = 16;
- ch = token_next_char(self);
- while ( is_digit(ch) || is_alpha(ch) )
- {
- *p++ = ch;
- ch = token_next_char(self);
- }
- *p = '\0';
- }
- else if ( ch == 'b' || ch == 'B' )
- {
- b = 2;
- ch = token_next_char(self);
- while ( (ch=='0')||(ch=='1') )
- {
- *p++ = ch;
- ch = token_next_char(self);
- }
- *p = '\0';
- }
- else if ( '0' <= ch && ch <= '7' )
- {
- b = 8;
- while ( '0' <= ch && ch <= '7' )
- {
- *p++ = ch;
- ch = token_next_char(self);
- }
- *p = '\0';
- }
- else
- {
- token_prev_char(self);
- /* made as 0 value */
- self->value.int_value = 0;
- self->current_token = finsh_token_type_value_int;
- return;
- }
- self->value.int_value = token_spec_number(buf, strlen(buf), b);
- self->current_token = finsh_token_type_value_int;
- }
- else
- {
- while ( is_digit(ch) )
- {
- value = value*10 + ( ch - '0' );
- ch = token_next_char(self);
- }
- self->value.int_value = value;
- self->current_token = finsh_token_type_value_int;
- }
- switch ( ch )
- {
- case 'l':
- case 'L':
- self->current_token = finsh_token_type_value_long;
- break;
- default:
- token_prev_char(self);
- break;
- }
- }
- /*use 64 bit number*/
- #define BN_SIZE 2
- static long token_spec_number(char* string, int length, int b)
- {
- char* p;
- int t;
- int i, j, shift=1;
- unsigned int bn[BN_SIZE], v;
- long d;
- p = string;
- i = 0;
- switch ( b )
- {
- case 16: shift = 4;
- break;
- case 8: shift = 3;
- break;
- case 2: shift = 1;
- break;
- default: break;
- }
- for ( j=0; j<BN_SIZE ; j++) bn[j] = 0;
- while ( i<length )
- {
- t = *p++;
- if ( t>='a' && t <='f' )
- {
- t = t - 'a' +10;
- }
- else if ( t >='A' && t <='F' )
- {
- t = t - 'A' +10;
- }
- else t = t - '0';
- for ( j=0; j<BN_SIZE ; j++)
- {
- v = bn[j];
- bn[j] = (v<<shift) | t;
- t = v >> (32 - shift);
- }
- i++;
- }
- d = (long)bn[0];
- return d;
- }
|