123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- /*
- * Copyright (C) 2020 Weber Yann
- *
- * This file is part of pyrpn.
- *
- * pyrpn 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 3 of the License, or
- * any later version.
- *
- * pyrpn 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 pyrpn. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "rpn_parse.h"
-
- /**@brief Macro for @ref rpn_ops member definition
- * @param NAME @ref rpn_lib.h symbol
- * @param s The short (1 char) symbol code
- * @param l The long (char*) symbole code
- */
- #define __op(NAME, s, l) {&NAME, &CODE_SZ(NAME), s, l}
- const rpn_op_t rpn_ops[] = {\
- __op(rpn_add, '+', "add"),\
- __op(rpn_sub, '-', "sub"),\
- __op(rpn_div, '/', "div"),\
- __op(rpn_mul, '*', "mul"),\
- __op(rpn_mod, '%', "mod"),\
- __op(rpn_neg, '!', "neg"),\
- __op(rpn_not, '~', "not"),\
- __op(rpn_and, '&', "and"),\
- __op(rpn_or, '|', "or"),\
- __op(rpn_xor, '^', "xor"),\
- __op(rpn_shr, 'r', ">>"),\
- __op(rpn_shl, 'l', "<<"),\
- __op(rpn_xchg, 'x', "xchg"),\
- __op(rpn_dup, 'd', "dup"),\
- __op(rpn_pop_op, 'p', "pop"),\
- };
- #undef __op
-
- int rpn_tokenizer_start(rpn_tokenizer_t *tokenizer, rpn_tokenized_t *dst,
- const char* expr, size_t argc)
- {
- int err;
-
- bzero(tokenizer, sizeof(rpn_tokenizer_t));
- tokenizer->orig = expr;
-
- tokenizer->toks = dst;
- tokenizer->toks->argc = argc;
- tokenizer->toks->tokens_sz = 0;
- tokenizer->toks->tokens = NULL;
-
-
- if(!(tokenizer->buff = strdup(expr)))
- {
- err = errno;
- snprintf(tokenizer->err_reason, 64,
- "Error duplicating expression for tokenization : %s",
- strerror(err));
- errno = err;
- return -1;
- }
- tokenizer->cur = tokenizer->buff;
-
- return 0;
- }
-
- rpn_token_t* rpn_tok(rpn_tokenizer_t *tokenizer)
- {
- char *token;
- rpn_token_t ret, *tmp, *res;
- int err;
-
- token = tokenizer->cur;
-
- if(!*token) // end of expression
- {
- rpn_tokenizer_free(tokenizer);
- return NULL;
- }
-
- while(*(tokenizer->cur))
- {
- if(*(tokenizer->cur) == ' ' ||
- *(tokenizer->cur) == '\n' ||
- *(tokenizer->cur) == '\t')
- {
- break;
- }
- tokenizer->cur++;
- tokenizer->chr_no++;
- }
- if(*(tokenizer->cur))
- {
- // not end, go on next chr for further rpn_tok calls
- *(tokenizer->cur) = '\0';
- tokenizer->cur++;
- tokenizer->chr_no++;
- }
-
- // we have a clean token '\0' terminated
- if(rpn_tokenize(token, &ret, tokenizer->err_reason) < 0)
- {
- errno = 0;
- return NULL;
- }
- if(ret.type == RPN_arg && ret.arg_n >= tokenizer->toks->argc)
- {
- // invalid argument number
- if(tokenizer->toks->argc)
- {
- snprintf(tokenizer->err_reason, 64,
- "Argument number is too big : should be in [0..%ld] but \"%s\" found",
- tokenizer->toks->argc - 1, token);
- }
- else
- {
- snprintf(tokenizer->err_reason, 64,
- "No argument accepted but \"%s\" found",
- token);
- }
- errno = EINVAL;
- return NULL;
- }
-
- if(tokenizer->toks->tokens_sz >= tokenizer->allocated_toks)
- {
- tokenizer->allocated_toks += 8;
- tmp = realloc(tokenizer->toks->tokens,
- sizeof(rpn_token_t) * tokenizer->allocated_toks);
- if(!tmp)
- {
- err = errno;
- snprintf(tokenizer->err_reason, 64,
- "Unable to realloc tokens list : %s",
- strerror(err));
- errno = err;
- return NULL;
- }
- tokenizer->toks->tokens = tmp;
- }
-
- res = &(tokenizer->toks->tokens[tokenizer->toks->tokens_sz]);
- *res = ret;
- tokenizer->toks->tokens_sz++;
- return res;
- }
-
- int rpn_tokenize(const char *token, rpn_token_t *dst, char error[64])
- {
- int rep;
- unsigned long num;
- const char *orig;
-
- if((rep = rpn_match_token_i(token)) >= 0)
- {
- dst->type = RPN_op;
- dst->op_n = rep;
- dst->op = &(rpn_ops[rep]);
- return 0;
- }
-
- orig = token;
-
- if(*token == 'A')
- {
- if(!token[1])
- {
- snprintf(error, 64,
- "Argument number is missing, lonely \"A \" found");
- return -1;
- }
- dst->type = RPN_arg;
- token++;
- }
- else
- {
- dst->type = RPN_val;
- }
-
- if(rpn_match_number(token, &num) < 0)
- {
- snprintf(error, 64,
- "Invalid %snumber : \"%s\"",
- dst->type == RPN_arg?"argument ":"constant ",
- orig);
- return -1;
- }
-
- if(dst->type == RPN_arg)
- {
- dst->arg_n = num;
- }
- else
- {
- dst->value = num;
- }
- return 0;
- }
-
- void rpn_tokenizer_free(rpn_tokenizer_t *tokenizer)
- {
- if(tokenizer->buff)
- {
- free(tokenizer->buff);
- bzero(tokenizer, sizeof(rpn_tokenizer_t));
- }
- }
-
- char* rpn_tokenized_expr(rpn_tokenized_t *tokens, char long_op)
- {
- size_t expr_sz, i;
- int err, written;
- char *cur, *tmp, *expr;
- rpn_token_t *token;
- int ALLOC_CHUNK=22; /* 64 bit uint is 20 decimal digit */
-
- #ifdef DEBUG
- if(!tokens)
- {
- dprintf(2, "Error, NULL ptr given to rpn_rokenize_expr");
- err = EINVAL;
- goto ret_err;
- }
- #endif
- errno = 0;
- err = 0;
- expr_sz = 0;
- expr_sz = 128;
- cur = expr = malloc(sizeof(char)*expr_sz);
- if(!expr)
- {
- err=errno;
- dprintf(2,"Error allocating memory for expression : %s",
- strerror(err));
- goto ret_err;
- }
- for(i=0; i<tokens->tokens_sz; i++)
- {
- token = &(tokens->tokens[i]);
- if(cur - expr >= expr_sz - ALLOC_CHUNK)
- {
- expr_sz += 128;
- tmp = realloc(expr, sizeof(char) * expr_sz);
- if(!tmp)
- {
- err=errno;
- dprintf(2,"Error allocating memory for expression : %s",
- strerror(err));
- goto ret_err;
- }
- cur = tmp + (cur - expr);
- expr = tmp;
- }
- switch(token->type)
- {
- case RPN_op:
- if(!long_op)
- {
- *cur = token->op->chr;
- cur[1] = ' ';
- cur[2] = '\0';
- written = 2;
- }
- else
- {
- written = snprintf(cur, ALLOC_CHUNK,
- "%s ", token->op->str);
- written--;
- }
- break;
- case RPN_arg:
- written = snprintf(cur, ALLOC_CHUNK,
- "A%lu ", token->arg_n);
- break;
- case RPN_val:
- written = snprintf(cur, ALLOC_CHUNK,
- "0x%lX ", token->value);
- break;
- default:
- #ifdef DEBUG
- dprintf(2,
- "Invalid token type encountered : %d\n",
- token->type);
- #endif
- err = EUCLEAN;
- goto free_err;
- }
- #ifdef DEBUG
- if(written > ALLOC_CHUNK)
- {
- dprintf(2, "Expression too long : %s",
- token->op->str);
- err = EINVAL;
- goto free_err;
- }
- #endif
- cur += written;
- }
-
- return expr;
-
- free_err:
- free(expr);
- ret_err:
- errno = err;
- return NULL;
- }
-
- const rpn_op_t* rpn_match_token(const char* token)
- {
- int rep;
- if((rep = rpn_match_token_i(token)) < 0)
- {
- return NULL;
- }
- return &(rpn_ops[rep]);
- }
-
- int rpn_match_token_i(const char* token)
- {
- unsigned char i;
- if(token[1] == '\0') //strlen(token) == 1
- {
- foreach_rpn_ops(i)
- {
- if(rpn_ops[i].chr == token[0])
- {
- return (int)i;
- }
- }
- return -1;
- }
- foreach_rpn_ops(i)
- {
- if(!strncmp(rpn_ops[i].str, token, 8))
- {
- return (int)i;
- }
- }
- return -1;
- }
-
- int rpn_match_number(const char* token, unsigned long *result)
- {
- char *endptr;
- unsigned long long res;
- int base;
-
- if(*token == '\0')
- {
- return -1;
- }
- base = 10;
- if(*token == '0' && token[1] != '\0')
- {
- token++;
- if(*token == 'x')
- {
- token++;
- base = 16;
- }
- else if(*token == 'o')
- {
- token++;
- base = 8;
- }
- else if(*token == 'b')
- {
- token++;
- base = 2;
- }
- }
- res = strtoull(token, &endptr, base);
- if(*endptr != '\0')
- {
- return -1;
- }
- *result = res;
- return 0;
- }
-
- size_t rpn_op_sz()
- {
- return sizeof(rpn_ops)/sizeof(rpn_op_t);
- }
|