Re: Conditional includes
- Posted by jimcbrown (admin) Nov 12, 2010
- 1323 views
irv said...
IF we could do that (I think it's impossible in Euphoria) it would make for much cleaner, easier to use code (The Glade IDE could, for example, be used to create an entire Eu program)
You're right, it is impossible in Euphoria.
However, you can use a preprocessor to work around this. Replace your call to routine_id() with get_rid() in funks.e as so...
export procedure do_fn(sequence s) atom rid = get_rid(s) printf(1,"do_fn sez routine_id is: %d\n",{rid}) --call_func(rid) end procedure
Then call main.ex like this:
eui -p e,ex:rid.ex main.ex
You'll need the following file in your include path somewhere, it's a helper library that the preprocessor, rid.ex, rewrites your program to use.
Name it save_rid.e
sequence allrids = "", allnames = "" public procedure save_rid(integer rid, sequence name) allrids = append(allrids, rid) allnames = append(allnames, name) end procedure public function get_rid(sequence name) integer i i = find(name, allnames) if i then return allrids[i] else return -1 end if end function
Now here's the output when I run main.ex:
File sez routine_id is 446 do_fn sez routine_id is: 446 Main sez routine_id is: 446
Here is rid.ex
--JBrown --combine.ex --global scopes aren't redefined --this MIGHT cause an error, however, euphoria should normally have an --error in that case too. --procedure-scope vars aren't saved, this makes code more readable --N/A if shroud is on --you can either choose not to combine files in a list, or --you can ignore include files on 1 dir (default: eu's include dir) --shrouding symbols is optional. --bug fixed: local symbols were being treated as global. --bug fixed: strings with \x were changed to \x\x. --bug fixed: file c:\myfile.e and myfile.e were the diffrent files. --added platform to sequence builtin --bug: using routine_id("abort_") gives error --"Unable to resolve routine id for abort" --to fix made routine_id-ing of builtin routines legal. -- concat.ex -- version 1.0 -- -- replacement for Euphoria's bind routine include std/cmdline.e include std/get.e include std/io.e include std/map.e include std/text.e include std/console.e include std/sequence.e include std/filesys.e integer slash if platform() = 3 then slash = '/' else slash = '\\' end if ----------------------------------------------------------------------------- -- code from RDS's ED color coding routines sequence charClass -- character classes constant DIGIT = 1, OTHER = 2, LETTER = 3, BRACKET = 4, QUOTE = 5, DASH = 6, WHITE_SPACE = 7, NEW_LINE = 8 charClass = repeat( OTHER, 255 ) charClass['a'..'z'] = LETTER charClass['A'..'Z'] = LETTER charClass['_'] = LETTER charClass['0'..'9'] = DIGIT charClass['['] = BRACKET charClass[']'] = BRACKET charClass['('] = BRACKET charClass[')'] = BRACKET charClass['{'] = BRACKET charClass['}'] = BRACKET charClass['\''] = QUOTE charClass['"'] = QUOTE charClass[' '] = WHITE_SPACE charClass['\t'] = WHITE_SPACE charClass['\n'] = NEW_LINE charClass['-'] = DASH --**** -- == Keyword Data include euphoria/keywords.e ----------------------------------------------------------------------------- integer globalState, -- 1 = just set, 2 = old flag routineFlag, -- 1 = last keyword was routine_id procState, -- 1 = keyword follows, 2 = inProc outFile -- file to write to globalState = 0 routineFlag = 0 procState = 0 sequence oldLocal, newLocal, included oldLocal = {} newLocal = {} included = {} constant EuPlace = getenv( "EUDIR" ), --Place = { "", EuPlace & "\\", EuPlace & "\\INCLUDE\\" } Place = { current_dir()&slash, EuPlace & slash, EuPlace & slash&"include"&slash, "" } ----------------------------------------------------------------------------- function findFile( sequence fName ) -- returns where a file is -- looks in the usual places -- look in the usual places --trace(1) if find(fName[length(fName)], {10, 13}) then fName = fName[1..length(fName)-1] end if for i = 1 to length( Place ) do if sequence( dir( Place[i] & fName ) ) then if platform() = 3 then return Place[i] & fName else return upper( Place[i] & fName ) end if end if end for printf( 1, "Unable to locate file %s.\n", {fName} ) --abort(0) end function ----------------------------------------------------------------------------- function replaceWord( sequence word ) -- replace obsolete builtin functions with valid names, so -- the resulting program does not crash with unresolved symbols return word end function ----------------------------------------------------------------------------- sequence funcName = "", nameSpace = "" integer inNameSpace = 0 function parseLine( sequence s ) -- parse a sequence into keywords -- and convert them integer at, char, i sequence out, word out = {} at = 1 while at <= length( s ) do -- get a character char = s[at] -- identifier if charClass[char] = LETTER then word = {} -- read until end while charClass[char] = LETTER or charClass[char] = DIGIT do -- add to word word = append( word, char ) -- next letter at += 1 char = s[at] end while -- routine flag routineFlag = equal( word, "routine_id" ) -- substitute? word = replaceWord( word ) -- global flag if equal( word, "global" ) then -- new occurance globalState = 1 elsif globalState = 1 then -- mark as used globalState = 2 end if if inNameSpace = 1 then inNameSpace = 2 nameSpace = word end if if equal( word, "namespace" ) then inNameSpace = 1 end if -- manage proc state if equal( word, "function" ) or equal( word, "procedure" ) or equal( word, "type" ) then if procState = 0 then -- beginning of definition procState = 1 elsif procState = 2 then -- end function/procedure procState = 0 word = word & sprintf(" save_rid(routine_id(\"%s\"), \"%s:%s\")", {funcName, nameSpace, funcName}) end if elsif procState = 1 then -- move state ahead procState = 2 globalState = 0 funcName = word end if -- substitute, if needed out = out & word -- number: handles hex as well elsif charClass[char] = DIGIT or char = '#' then word = {} -- read until end while charClass[char] = DIGIT or charClass[char] = LETTER or char = '#' do -- add to word word = append( word, char ) -- next letter at += 1 char = s[at] end while -- accumulated number out = out & word -- comment elsif char = '-' and s[at+1] = '-' then -- comment out = out & s[at..length(s)] -- move past end at = length(s)+1 -- character literal elsif char = '\'' then at += 1 if s[at] = '\\' then -- special at += 1 word = "'\\" & s[at] & "'" else -- normal word = "'" & s[at] & "'" end if -- move past quote at += 2 -- accumulate out = out & word -- quote elsif char = '"' then word = {'"'} while 1 do -- move ahead at += 1 if at > length(s) then exit end if -- special? if at <= length(s) and s[at] = '\\' then at += 1 --word = word & s[at-1] & s[at] word = word & '\\' & s[at] -- prevent reading as quote s[at] = ' ' elsif at <= length(s) then word = word & s[at] end if -- end of quote? if at <= length(s) and s[at] = '"' then -- move ahead and exit at += 1 exit end if end while -- handle routine_id if routineFlag then -- remove quotes word = word[2..length(word)-1] word = replaceWord(word) -- re-apply quotes word = '"' & word & '"' end if -- accumulated out = out & word -- delimiter else out = out & char at += 1 end if end while if inNameSpace = 2 then inNameSpace = 0 out = {out, "include save_rid.e\n" } end if return out end function ----------------------------------------------------------------------------- function getIncludeName( sequence data ) -- if the statement is an include statement, return the file name integer at -- include statement missing? if not match( "include ", data ) then return "" end if -- trim white space while charClass[ data[1] ] = WHITE_SPACE do data = data[2..length( data ) ] end while -- line feed? if find( '\n', data ) then data = data[1..length(data)-1] end if if find( '\r', data ) then data = data[1..length(data)-1] end if -- not first statement? if not equal( data[1..8], "include " ) then -- not an include statement return "" else -- remove statement data = data[9..length(data)] end if -- remove data after space at = find( ' ', data ) if at then data = data[1..at-1] end if return data end function ----------------------------------------------------------------------------- function trimer(sequence s) sequence t integer u if s[length(s)] = '\n' then s = s[1..length(s)-1] end if if s[length(s)] = '\r' then s = s[1..length(s)-1] end if t = reverse(s) u = find(slash, t) if not u then return s end if t = t[1..u-1] s = reverse(t) return s end function function includable(sequence name) return 0 end function ----------------------------------------------------------------------------- without warning procedure parseFile( sequence fName ) integer inFile sequence newPrior, oldPrior, includeName, oldNameSpace = nameSpace object data, seqall seqall = "" nameSpace = fName -- find the file fName = findFile( fName ) -- already part of the file? if find( fName, included ) then nameSpace = oldNameSpace return else included = append( included, fName ) end if -- store locals and clear oldPrior = oldLocal newPrior = newLocal oldLocal = {} newLocal = {} -- write header puts( outFile, "\n" ) inFile = open( fName, "r" ) while 1 do -- read a line data = gets( inFile ) -- end of file? if integer( data ) then exit end if -- include file? includeName = getIncludeName( data ) if length( includeName ) and includable(trimer(includeName)) then -- include the file parseFile( includeName ) elsif length(includeName) then --no parse --puts( outFile, data ) seqall = append(seqall, data) else -- translate data = parseLine( data ) -- output --puts( outFile, data ) if length(data) and sequence(data[1]) then seqall &= data else seqall = append(seqall, data) end if end if end while close( inFile ) --end of file header integer gotit = 0 for i = 1 to length(seqall) do if equal(seqall[i], "include save_rid.e\n") then gotit = 1 end if end for if not gotit then seqall = { "include save_rid.e\n" } & seqall end if for i = 1 to length(seqall) do puts( outFile, seqall[i] ) end for puts( outFile, "\n" ) -- restore locals oldLocal = oldPrior newLocal = newPrior end procedure with warning ----------------------------------------------------------------------------- export function preprocess(sequence inFileName, sequence outFileName, sequence optParams) -- make sure they are different if equal( inFileName, outFileName ) then puts( 1, "File names must be different!\n" ) return 1 end if -- open the file outFile = open( outFileName, "w" ) -- process the input file parseFile( inFileName ) -- close the output file close( outFile ) return 0 end function ----------------------------------------------------------------------------- constant cmd_params = { { "i", 0, "Input filename", { NO_CASE, HAS_PARAMETER, ONCE, "filename" } }, { "o", 0, "Output filename", { NO_CASE, HAS_PARAMETER, ONCE, "filename" } } } procedure run() object optParams optParams = {} -- read the command line map:map params = cmd_parse(cmd_params) object inFileName=map:get(params, "i"), outFileName=map:get(params, "o") -- get input file if atom(inFileName) then inFileName = prompt_string( "File to concatonate? " ) if length( inFileName ) = 0 then abort(0) end if end if -- get output file if atom(outFileName) then outFileName = prompt_string( "File to create? " ) if length( outFileName ) = 0 then abort(0) end if end if -- make sure they are different if preprocess( inFileName, outFileName, optParams ) then abort(0) end if end procedure ifdef not EUC_DLL then run() end ifdef