#!/bin/sh ## The scanner generartor (f)lex and its options ## LEXBIN="flex" LEXOPT="-L" ## The MuPAD module generator and its options ## MMGBIN="mmg" LEXLIB="-I/usr/local/gnu/include -L/usr/local/gnu/lib -L/usr/local/lib -lfl" MMGOPT="-v -color -a static ${LEXLIB}" PrintInfo() { cat< DOM_BOOL ) x::close() -- Closes the current file (==> DOM_NULL ) x::token() -- Returns the next token (==> DOM_INT ) x::text() -- Returns the text of the token (==> DOM_STRING) x::line() -- Returns the current line number (==> DOM_INT ) x::back() -- Put back the last token (==> DOM_BOOL ) Tokens are non-negative integers. x::token() returns the token 0 when the end of the input file is reached. The following example 'demo.l' defines a very simple scanner 'demo', which allows to count the lines of an input file. Call './mkscan demo' to generate the scanner module: %{ enum { EOFILE=0, UNKNOWN=1, LINE=2 }; %} nline [\n] %% {nline} { return( LINE ); } %% The dynamic scanner module 'demo.mdm' will be placed in the current working directory and can be used within a MuPAD session: >> module( "demo" ): >> demo::open( "demo.l" ): >> l:=0: while demo::token()=2 do l:=l+1 end_while: l; >> demo::close(); The dynamic scanner module 'demo.mdm' will be placed in the current working For further information refer to the (f)lex manual and the files 'demo.yy.c' and 'demo.C' created by 'mkscan'. EOF } CreateModuleSource() { CreateLexCode $1 echo '## Creating the module source code #################################' echo '##' echo mkscan '==>' $1.C cat< $1.C /******************************************************************************/ /* FILE : ???.C -- A module interface for scanners generated by (f)lex */ /* AUTHOR : Andreas Sorgatz (andi@uni-paderborn.de) */ /* CREATED: 24. Nov. 1996 */ /* CHANGED: 25. Nov. 1996 */ /******************************************************************************/ // Options for the MuPAD Module Generator ////////////////////////////////////// // MMG( info = "Dynamic scanner module for (f)lex scanners" ) // Internal variables - do not change this !!! ///////////////////////////////// // #define ScanLen 1024 // Length of string buffers static char ScanTokenString[ScanLen] = ""; // Token string buffer static char* ScanFileName = NULL; // Name of current file static long ScanLine = 1; // Current line number static short ScanBack = 1; // A token was put back ? // ECHO returns unknown Tokens (UNKNOWN) - refer to 'man flex' and 'lex.yy.c'. // The constant UNKNOWN has to be defined in 'lex.yy.c'. // #define ECHO { return( UNKNOWN ); } // Include the C source code generated by (f)lex - do not change this !!! ////// // #include "lex.yy.c" // // ---------------------------------------------------------------------------- extern "C" { `cat $1.yy.c` } // ---------------------------------------------------------------------------- // The scanner functions: open, close, token, text, line, back ///////////////// // /******************************************************************************/ /* FUNCTION: scan::open( "FILENAME" ) - Open a file to be scanned */ /******************************************************************************/ MFUNC( open, MCnop ) { MFnargsCheck(1); MFargCheck(1,DOM_STRING); if( ScanFileName != NULL ) { ScanFileName = NULL; ScanLine = 1; fclose(yyin); } if( (yyin = fopen(MFstring(MFarg(1)),"r")) == NULL ) MFreturn( MFcopy(MVfalse) ); ScanFileName = MFstring(MFarg(1)); ScanTokenString[0] = '\0'; yyrestart(yyin); MFreturn( MFcopy(MVtrue) ); } MFEND /******************************************************************************/ /* FUNCTION: scan::close() - Close the currently scanned file */ /******************************************************************************/ MFUNC( close, MCnop ) { MFnargsCheck(0); if( ScanFileName != NULL ) { ScanFileName = NULL; fclose(yyin); } MFreturn( MFcopy(MVnull) ); } MFEND /******************************************************************************/ /* FUNCTION: scan::token() - Return the next token */ /******************************************************************************/ MFUNC( token, MCnop ) { MFnargsCheck(0); if( ScanFileName == NULL ) MFerror( "Open input file first" ); MTcell token = MFlong(yylex()); ScanBack = 0; if( yyleng >= ScanLen ) MFerror( "Fatal error, token exceeded max length" ); for( int i = 0; i < yyleng; ) { ScanTokenString[ i] = yytext[i]; ScanTokenString[++i] = 0; } MFreturn( token ); } MFEND /******************************************************************************/ /* FUNCTION: scan::text() - Return the string of the last scanned token */ /******************************************************************************/ MFUNC( text, MCnop ) { MFnargsCheck(0); if( ScanBack ) MFreturn( MFstring("") ); MFreturn( MFstring(ScanTokenString) ); } MFEND /******************************************************************************/ /* FUNCTION: scan::back() - Put back the last scanned token */ /******************************************************************************/ MFUNC( back, MCnop ) { MFnargsCheck(0); if( ScanBack ) MFreturn( MFcopy(MVfalse) ); ScanBack = 1; yyless(0); MFreturn( MFcopy(MVtrue) ); } MFEND /******************************************************************************/ /* FUNCTION: scan::line() - Return the current line number */ /******************************************************************************/ MFUNC( line, MCnop ) { MFnargsCheck(0); MFreturn( MFlong(ScanLine) ); } MFEND EOF if [ ! -r $1.C ] ; then echo "Creation failed: module source file \"$1.C\"" echo ' ' exit 2 fi } ############################################################################## # CreateModuleHelp ( BASENAME ) ############################################################################## CreateModuleHelp() { echo '## Creating the module help file ###################################' echo '##' echo mkscan '==>' $1.mdh cat< $1.mdh MODULE $1 - A MuPAD module interface to a (f)lex scanner INTRODUCTION This module defines a MuPAD interface to a scanner created with the scanner generator (f)lex. The function token() returns non-negative integers, with EOFILE=0. The string of the current token can be ex- tracted with text(). back() allows the user to put back the current token to be re-scanned with the next call of the function token(). For technical information please refer to the manual of flex(1) and also to the source file of this module. MuPAD scanner modules are static modules which will not be unloaded automatically. They can be created with the shell script 'mkscan', which is available from official MuPAD ftp sites. INTERFACE doc, back, close, line, open, text, token NAME $1::doc - Online documentation SYNOPSIS $1::doc() $1::doc( func ) ARGUMENTS func - Function name without the prefix "$1::" (DOM_STRING) DESCRIPTION Displays a brief description of this scanner module , respectively the function $1::'func'. EXAMPLE: >> $1::doc("token"); [...] SEE ALSO module::help NAME $1::back - Puts back the current token to be re-scanned later SYNOPSIS $1::back() ARGUMENTS - DESCRIPTION Puts back the current token, to be re-scanned with the next call of the function token(). back() cannot be called again before the put back token was re-scanned by token(). The function returns TRUE if the token was put back and FALSE if not. NOTE: After back() was called, text() returns the empty character string ("") until the token is re-scanned by token(). EXAMPLE: >> $1::token(); 13 >> $1::back(); TRUE >> $1::token(), $1::token(); 13, 7 SEE ALSO $1::token NAME $1::close - Closes the current input file SYNOPSIS $1::close() ARGUMENTS - DESCRIPTION Closes the current input file of this scanner module. The function returns the value DOM_NULL. EXAMPLE: >> $1::open("test"); TRUE >> $1::close(); SEE ALSO $1::open NAME $1::line - Returns the current line number. SYNOPSIS $1::line() ARGUMENTS - DESCRIPTION Returns the current line number. The line numbers starts with 1. EXAMPLE: >> $1::open("test"); TRUE >> $1::line(); 1 SEE ALSO $1::text NAME $1::open - Opens a new scanner input file SYNOPSIS $1::open( file ) ARGUMENTS file - A file name (DOM_STRING) DESCRIPTION Opens a new scanner input file. If there is an open scanner file of this scanner module then it is closed before. The function returns TRUE if "file" has been opened and FALSE otherwise. EXAMPLE: >> $1::open("test"); TRUE >> $1::token(); 2 SEE ALSO $1::close, $1::token NAME $1::text - Returns the character string of the current token SYNOPSIS $1::text() ARGUMENTS - DESCRIPTION Returns the character string of the current token. Before the first token is read as well as at the end of the input file this function returns the empty character string (""). This is also be done when back() was called and the token was not re-scanned yet. EXAMPLE: >> $1::text(); "42" >> $1::token(); 0 >> $1::text(); "" SEE ALSO $1::line, $1::token NAME $1::token - Returns the next token read from the input file SYNOPSIS $1::token() ARGUMENTS - DESCRIPTION Returns the next token read from the current input file. Tokens are non-negative integers with EOFILE=0, UNKNOWN=1, ... EXAMPLE: >> $1::token(); 2 >> $1::text(); "while" >> $1::token(); 0 SEE ALSO $1::line, $1::text EOF if [ ! -r $1.mdh ] ; then echo "Creation failed: module help file \"$1.mdh\"" echo ' ' exit 3 fi } ############################################################################## # CreateLexCode ( BASENAME ) ############################################################################## CreateLexCode() { echo '## Creating (f)lex scanner source code #############################' echo '##' echo $1.l '==>' $1.yy.c if [ ! -r $1.l ] ; then echo "Cannot read: (f)lex input file \"$1.l\"" echo ' ' exit 1 fi ${LEXBIN} ${LEXOPT} -o$1.yy.c $1.l if [ ! -r $1.yy.c ] ; then echo "Creation failed: (f)lex output file \"$1.yy.c\"" echo ' ' exit 1 fi } ############################################################################## # CreateModule ( BASENAME ) ############################################################################## CreateModule() { echo '## Compiling the dynamic scanner module ############################' echo '##' echo $1.l, $1.C '==>' $1.mdm ${MMGBIN} ${MMGOPT} $2 $1.C } ############################################################################## # MAIN ############################################################################## if [ $# -eq 0 ] ; then PrintInfo | more exit 0 fi CREATE="YES" # Compile a dynamic scanner module ? Yes! SMNAME="NONAME" # The scanner module name ? Unknown ! while [ $# -gt 0 ] ; do if [ "$1" = "-c" ] ; then CREATE="NO" shift else SMNAME="$1" shift fi done if [ "$SMNAME" = "noname" ] ; then echo "usage: mkscan [-c] name" echo ' ' exit 4 fi CreateModuleSource $SMNAME CreateModuleHelp $SMNAME if [ "$CREATE" = "YES" ] ; then CreateModule $SMNAME fi echo ' '