1/** @file ginsh_lexer.lpp 2 * 3 * Lexical analyzer definition for ginsh. 4 * This file must be processed with flex. */ 5 6/* 7 * GiNaC Copyright (C) 1999-2022 Johannes Gutenberg University Mainz, Germany 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24 25/* 26 * Definitions 27 */ 28 29%option nounput 30 31%pointer 32 33%{ 34#ifdef HAVE_CONFIG_H 35#include "config.h" 36#endif 37 38#include "ginsh.h" 39#include "ginsh_parser.hpp" 40 41using namespace std; 42using namespace GiNaC; 43 44#define YY_INPUT(buf, result, max_size) (result = ginsh_input(buf, max_size)) 45 46// Table of all used symbols 47sym_tab syms; 48 49// Type of symbols to generate (real or complex) 50unsigned symboltype = domain::complex; 51 52// lex input function 53static int ginsh_input(char *buf, int max_size); 54%} 55 56 /* Abbreviations */ 57D [0-9] 58E [elEL][-+]?{D}+ 59A [a-zA-Z_] 60AN [0-9a-zA-Z_] 61 62 63/* 64 * Lexical rules 65 */ 66 67%% 68[ \t\n]+ /* skip whitespace */ 69\\$ /* skip line continuations */ 70"//".* /* skip comments starting with "//" */ 71^"#".* /* skip lines starting with "#" */ 72^"!".* system(yytext + 1); /* execute shell command */ 73 74 /* special values */ 75Pi yylval = Pi; return T_LITERAL; 76Euler yylval = Euler; return T_LITERAL; 77Catalan yylval = Catalan; return T_LITERAL; 78FAIL yylval = *new fail(); return T_LITERAL; 79I yylval = I; return T_NUMBER; 80Digits yylval = (long)Digits; return T_DIGITS; 81 82 /* keywords */ 83quit|exit return T_QUIT; 84warranty return T_WARRANTY; 85print return T_PRINT; 86iprint return T_IPRINT; 87print_latex return T_PRINTLATEX; 88print_csrc return T_PRINTCSRC; 89time return T_TIME; 90xyzzy return T_XYZZY; 91inventory return T_INVENTORY; 92look return T_LOOK; 93score return T_SCORE; 94complex_symbols return T_COMPLEX_SYMBOLS; 95real_symbols return T_REAL_SYMBOLS; 96 97 /* comparison */ 98"==" return T_EQUAL; 99"!=" return T_NOTEQ; 100"<=" return T_LESSEQ; 101">=" return T_GREATEREQ; 102 103 /* last 1..3 expressions */ 104\% return T_QUOTE; 105\%\% return T_QUOTE2; 106\%\%\% return T_QUOTE3; 107 108 /* numbers */ 109{D}+ | 110"#"{D}+"R"{AN}+ | 111"#b"([01])+ | 112"#o"[0-7]+ | 113"#x"[0-9a-fA-F]+ | 114{D}+"."{D}*({E})? | 115{D}*"."{D}+({E})? | 116{D}+{E} yylval = numeric(yytext); return T_NUMBER; 117 118 /* symbols */ 119{A}{AN}* { 120 sym_tab::const_iterator i = syms.find(yytext); 121 if (i == syms.end()) { 122 if (symboltype == domain::complex) { 123 symbol tmp(yytext); 124 syms[yytext] = tmp; 125 yylval = tmp; 126 } else { 127 realsymbol tmp(yytext); 128 syms[yytext] = tmp; 129 yylval = tmp; 130 } 131 } else 132 yylval = i->second; 133 return T_SYMBOL; 134 } 135 136 /* wildcards */ 137\${D}+ yylval = wild(atoi(yytext + 1)); return T_LITERAL; 138 139 /* everything else */ 140. return *yytext; 141 142%% 143 144 145/* 146 * Routines 147 */ 148 149static int line_length = 0; 150static char *line_read = nullptr; 151static char *line_ptr; 152 153// Input function that uses libreadline for interactive input 154static int ginsh_input(char *buf, int max_size) 155{ 156 int result; 157#if defined(YY_CURRENT_BUFFER) 158 if (YY_CURRENT_BUFFER->yy_is_interactive) { 159#else 160 if (yy_current_buffer->yy_is_interactive) { 161#endif 162#ifdef HAVE_LIBREADLINE 163 // Do we need to read a new line? 164 int actual; 165 if (line_length == 0) { 166 167 // Free old line 168 if (line_read) 169 free(line_read); 170 171 // Read new line, prompt "> " 172 line_read = line_ptr = readline("> "); 173 174 // EOF? 175 if (!line_read) { 176 line_length = 0; 177 return YY_NULL; 178 } 179 180 // Add non-empty lines to history 181 line_length = strlen(line_read) + 1; 182 if (line_length > 1) 183 add_history(line_read); 184 185 // Reappend trailing '\n' which is stripped by readline() 186 line_read[line_length - 1] = '\n'; 187 } 188 189 // Copy data to lex buffer 190 actual = line_length > max_size ? max_size : line_length; 191 memcpy(buf, line_ptr, actual); 192 line_length -= actual; 193 line_ptr += actual; 194 result = actual; 195#else 196 printf("> "); fflush(stdout); 197 int c = '*', n; 198 for (n = 0; n < max_size && (c = getc(yyin)) != EOF && c != '\n'; ++n) 199 buf[n] = (char)c; 200 if (c == '\n') 201 buf[n++] = (char)c; 202 if (c == EOF && ferror(yyin)) 203 YY_FATAL_ERROR("input in flex scanner failed"); 204 result = n; 205#endif 206 } else if (((result = fread(buf, 1, max_size, yyin)) == 0) && ferror(yyin)) 207 YY_FATAL_ERROR("input in flex scanner failed"); 208 209 return result; 210} 211 212// List of input files to be processed 213int num_files = 0; 214char **file_list = nullptr; 215 216// EOF encountered, connect to next file. If this was the last file, 217// connect to stdin. If this was stdin, terminate the scanner. 218int yywrap() 219{ 220 if (yyin == stdin) 221 return 1; 222 223 fclose(yyin); 224 if (num_files) { 225 yyin = fopen(*file_list, "r"); 226 if (yyin == nullptr) { 227 cerr << "Can't open " << *file_list << endl; 228 return 1; 229 } 230 num_files--; 231 file_list++; 232 } else 233 yyin = stdin; 234 return 0; 235} 236