/* GENIUS Calculator * Copyright (C) 1997-2007 Jiri (George) Lebl * * Author: Jiri (George) Lebl * * This file is part of Genius. * * Genius 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 * (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, see . */ %{ #include "config.h" #include #include #include #include #include #include "mpwrap.h" #include "eval.h" #include "dict.h" #include "calc.h" #include "parse.h" #include "util.h" #include "binreloc.h" int lex_fd[2]; int first_tok = STARTTOK; int return_ret = FALSE; int parenth_depth = 0; int lex_init = TRUE; extern GSList *gel_parsestack; static int matrix_entry = 0; static GSList *matrix_entry_stack = NULL; /* Ugly warning avoiding */ #define yywrap() 1 #define YY_SKIP_YYWRAP #ifdef FLEX_SCANNER int yylex(void); #endif #define NO_RET {return_ret = FALSE;} #define DO_RET { \ if(!parenth_depth) \ return_ret = TRUE; \ else \ return_ret = FALSE; \ } static GHashTable *fp_hash = NULL; void gel_lexer_open(FILE *fp); void gel_lexer_parse(FILE *fp); void gel_lexer_close(FILE *fp); void gel_lexer_open(FILE *fp) { YY_BUFFER_STATE buf; if(!fp_hash) fp_hash = g_hash_table_new(NULL, NULL); buf = g_hash_table_lookup(fp_hash, fp); if(buf) return; buf = yy_create_buffer(fp, YY_BUF_SIZE); g_hash_table_insert(fp_hash, fp, buf); } void gel_lexer_parse(FILE *fp) { YY_BUFFER_STATE buf; g_assert(fp_hash); buf = g_hash_table_lookup(fp_hash, fp); yy_switch_to_buffer(buf); yyparse(); } void gel_lexer_close(FILE *fp) { YY_BUFFER_STATE buf; /* don't close the stdin */ if(fp == stdin) return; g_assert(fp_hash); buf = g_hash_table_lookup(fp_hash, fp); yy_delete_buffer(buf); g_hash_table_remove(fp_hash, fp); } %} %% %{ if(lex_init) { return_ret = FALSE; parenth_depth = 0; matrix_entry = 0; matrix_entry_stack = NULL; lex_init = FALSE; } if(first_tok!=INT_MAX) { int i = first_tok; first_tok = INT_MAX; return i; } %} #.*$ ; /*comment, ignore*/ ^[ ]*load[ ]+<([^>]|\\>)*>[ ]*$ { char *s; char *end; char *dir; if(gel_parsestack || parenth_depth) {REJECT;} s=strchr(yytext,'<')+1; /*find the beginning*/ end=strrchr(yytext,'>'); /*find the end*/ s = unescape_string(s,end,NULL); dir = gbr_find_data_dir (DATADIR); yylval.id = g_build_filename (dir, "genius", s, NULL); g_free (dir); g_free(s); DO_RET; return LOADFILE; } ^[ ]*load[ ]+[^ ].*$ { char *s; if(gel_parsestack || parenth_depth) {REJECT;} s=strchr(yytext,'d')+1; /*move after the load*/ /*btw from the above RE we know this will work*/ while(*s==' ' || *s=='\t') s++; yylval.id = g_strdup(s); DO_RET; return LOADFILE_GLOB; } ^[ ]*cd[ ]+[^ ].*$ { char *s; if(gel_parsestack || parenth_depth) {REJECT;} s=strchr(yytext,'d')+1; /*move after the cd*/ /*btw from the above RE we know this will work*/ while(*s==' ' || *s=='\t') s++; yylval.id = g_strdup(s); DO_RET; return CHANGEDIR; } ^[ ]*plugin[ ]+[^ ].*$ { char *s; if(gel_parsestack || parenth_depth) {REJECT;} s=strchr(yytext,'n')+1; /*move after the plugin*/ /*btw from the above RE we know this will work*/ while(*s==' ' || *s=='\t') s++; yylval.id = g_strdup(s); DO_RET; return LOAD_PLUGIN; } ^[ ]*pwd[ ]*$ { if(gel_parsestack || parenth_depth) {REJECT;} DO_RET; return PWD; } ^[ ]*ls[ ]+[^ ].*$ { char *s; if(gel_parsestack || parenth_depth) {REJECT;} s=strchr(yytext,'s')+1; /*move after the ls*/ /*btw from the above RE we know this will work*/ while(*s==' ' || *s=='\t') s++; yylval.id = g_strdup(s); DO_RET; return LS_ARG; } ^[ ]*ls[ ]*$ { if(gel_parsestack || parenth_depth) {REJECT;} DO_RET; return LS; } ^[ ]*help[ ]+[^ ].*$ { char *s; if(gel_parsestack || parenth_depth) {REJECT;} s=strchr(yytext,'p')+1; /*move after the help*/ /*btw from the above RE we know this will work*/ while(*s==' ' || *s=='\t') s++; yylval.id = g_strdup(s); DO_RET; return HELP_ARG; } ^[ ]*help[ ]*$ { if(gel_parsestack || parenth_depth) {REJECT;} DO_RET; return HELP; } ";" { if (matrix_entry && GPOINTER_TO_INT(matrix_entry_stack->data) == 0) { return NEXTROW; } DO_RET; return SEPAR; } \"([^"]|\\\")*\" { DO_RET; yylval.id = unescape_string(&yytext[1],NULL,NULL); /*kill the trailing "*/ yylval.id[strlen(yylval.id)-1]='\0'; return STRING; } == { NO_RET; return EQ_CMP; } != { NO_RET; return NE_CMP; } "<>" { NO_RET; return NE_CMP; } "<=>" { NO_RET; return CMP_CMP; } "<=" { NO_RET; return LE_CMP; } ">=" { NO_RET; return GE_CMP; } "<" { NO_RET; return LT_CMP; } ">" { NO_RET; return GT_CMP; } = { NO_RET; return EQUALS; } := { NO_RET; return DEFEQUALS; } not { NO_RET; return LOGICAL_NOT; } and { NO_RET; return LOGICAL_AND; } xor { NO_RET; return LOGICAL_XOR; } or { NO_RET; return LOGICAL_OR; } while { NO_RET; return WHILE; } until { NO_RET; return UNTIL; } for { NO_RET; return FOR; } sum { NO_RET; return SUM; } prod { NO_RET; return PROD; } do { NO_RET; return DO; } to { NO_RET; return TO; } by { NO_RET; return BY; } in { NO_RET; return IN; } if { NO_RET; return IF; } then { NO_RET; return THEN; } else { NO_RET; return ELSE; } function { NO_RET; return FUNCTION; } parameter { NO_RET; return PARAMETER; } call { NO_RET; return CALL; } return { NO_RET; return RETURNTOK; } bailout { DO_RET; return BAILOUT; } exception { DO_RET; return EXCEPTION; } continue { DO_RET; return CONTINUE; } break { DO_RET; return BREAK; } mod { NO_RET; return MOD; } null { DO_RET; return '.'; } "@(" { parenth_depth++; if (matrix_entry_stack != NULL) matrix_entry_stack->data = GINT_TO_POINTER (GPOINTER_TO_INT(matrix_entry_stack->data) + 1); NO_RET; return AT; } \.\.\. { NO_RET; return THREEDOTS; } [[][\t ]* { matrix_entry++; parenth_depth++; matrix_entry_stack = g_slist_prepend (matrix_entry_stack, GINT_TO_POINTER (0)); NO_RET; return '['; } [\t ]*[]] { GSList *li; matrix_entry--; parenth_depth--; li = matrix_entry_stack; matrix_entry_stack = g_slist_remove_link (matrix_entry_stack, li); g_slist_free_1 (li); DO_RET; return ']'; } [({] { parenth_depth++; if (matrix_entry_stack != NULL) matrix_entry_stack->data = GINT_TO_POINTER (GPOINTER_TO_INT(matrix_entry_stack->data) + 1); NO_RET; return yytext[0]; } [)][ \t]*i { parenth_depth--; if (matrix_entry_stack != NULL) matrix_entry_stack->data = GINT_TO_POINTER (GPOINTER_TO_INT(matrix_entry_stack->data) - 1); DO_RET; return MAKEIMAGPARENTH; } [)}] { parenth_depth--; if (matrix_entry_stack != NULL) matrix_entry_stack->data = GINT_TO_POINTER (GPOINTER_TO_INT(matrix_entry_stack->data) - 1); DO_RET; return yytext[0]; } [a-zA-Z_][a-zA-Z0-9_]* { /* identifier*/ yylval.id = g_strdup(yytext); DO_RET; return FUNCID; } [1-9][0-9]*i?[ ][1-9][0-9]*i?[/][1-9][0-9]*i? { mpw_init(yylval.val); mpw_set_str(yylval.val,yytext,10); DO_RET; return NUMBER; } [0-9]+i { mpw_init(yylval.val); mpw_set_str_complex_int(yylval.val,yytext,10); DO_RET; return NUMBER; } [0-9]*\.[0-9]+[eE@][-+]?[0-9]+i | [0-9]+[eE@][-+]?[0-9]+i | [0-9]*\.[0-9]+i { char *s; if(yytext[0] == '.') s = g_strconcat("0",&yytext[0],NULL); else s = g_strdup(yytext); mpw_init(yylval.val); mpw_set_str_complex(yylval.val,s,10); g_free(s); DO_RET; return NUMBER; } [0-9]*\.[0-9]+[eE@][-+]?[0-9]+ | [0-9]+[eE@][-+]?[0-9]+ | [0-9]*\.[0-9]+ { char *s; if(yytext[0] == '.') s = g_strconcat("0",&yytext[0],NULL); else s = g_strdup(yytext); mpw_init(yylval.val); mpw_set_str_float(yylval.val,s,10); g_free(s); DO_RET; return NUMBER; } ([1-3][0-9]|[1-9])\\[0-9a-zA-Z]+ { char *s; int base; s=g_malloc(strlen(yytext)-2); /*minus 3 and plus 1*/ sscanf(yytext,"%d\\%[0-9a-zA-Z]s",&base,s); if(base>36) { g_free(s); REJECT; } mpw_init(yylval.val); mpw_set_str_int(yylval.val,s,base); g_free(s); DO_RET; return NUMBER; } 0x[0-9a-fA-F]+ | 0[0-7]+ | [0-9]+ { mpw_init(yylval.val); mpw_set_str_int(yylval.val,yytext,0); DO_RET; return NUMBER; } \\\n { gel_incr_file_info(); } [\t ]*\n { gel_incr_file_info(); if(matrix_entry) { return NEXTROW; } else if(return_ret) { first_tok = 0; return '\n'; } } [ \t\r]+ ; /*ignore whitespace*/ \.\+ { DO_RET; return ELTELTPLUS; } \.\- { DO_RET; return ELTELTMINUS; } \.\* { DO_RET; return ELTELTMUL; } \.\/ { DO_RET; return ELTELTDIV; } \.\\ { DO_RET; return ELTELTBACKDIV; } \.\% { DO_RET; return ELTELTMOD; } \.\^ { DO_RET; return ELTELTEXP; } \.\' { DO_RET; return TRANSPOSE; } [!][!] { DO_RET; return DOUBLEFACT; } [!'] { DO_RET; return yytext[0]; } [@^*/%+-`] { NO_RET; return yytext[0]; } \. { DO_RET; return '.'; } \| { DO_RET; return '|'; } <> { gel_got_eof = TRUE; return '\n'; } . { NO_RET; return yytext[0]; } %% int my_yyinput(void); int my_yyinput(void) { return input(); } /* avoid unused warnings, kind of bogus */ /* Apparently this no worky, so don't do it */ #if 0 #ifdef FLEX_SCANNER void fake_fake_fake (void); void fake_fake_fake (void) { yy_flex_realloc (NULL, 0); yyunput (0, NULL); } #endif #endif /* Dropping support for tabs as separators in matrix entry as of 1.0.1 if we want to readd it, just add the following after "ignore whitespace" line above ^[\t ][\t ]* ; [\t ]*,[\t ]* { return ','; } [\t][\t ]* { if(matrix_entry) return ','; } */