home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / powergui / shipapp / genprags / genprags.lx < prev    next >
Text File  |  1996-10-29  |  10KB  |  313 lines

  1. /*-----------------------------------------------------------------------
  2.    genprags.lx  - The primary purpose of this macro is to
  3.       generate the alloc_text pragmas for initialization,
  4.       termination, and static functions.   If you have a command line
  5.       REXX interpreter available, you can copy this file to genprags.cmd
  6.       and run it from the command line.   If this option is available it
  7.       is recommended since this program can take a while and will lock
  8.       up the edit session while it is running as a macro.
  9.  
  10.       The macro functions by generating and parsing the
  11.       assembler code (-Fa) for all specified files. Static
  12.       functions are identified because they have a PROC
  13.       statement with no cooresponding PUBLIC statement.
  14.       The static functions identified in this manner are
  15.       searched for various tokens to determine the segment
  16.       they should be placed in and the appropriate
  17.       alloc_text pragmas generated.
  18.  
  19.    Requires as inout:
  20.     wildCardFileName   - files to process of the form '*.cpp'
  21.  
  22.    Generates as output:
  23.     initprag.h
  24.  
  25.   Copyright (C) 1994, Law, Leong, Love, Olson, Tsuji.
  26.   Copyright (c) 1997 John Wiley & Sons, Inc. 
  27. -----------------------------------------------------------------------*/
  28.  
  29. call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  30. call SysLoadFuncs
  31.  
  32. /* set up to run as either a macro or a command file */
  33. parse upper source osname . me
  34. me = strip(me)
  35. lastDot = lastPos('.', me)
  36. if substr(me, lastDot) = ".LX" then do
  37.    isMacro = 1
  38. end
  39. else do
  40.    isMacro = 0
  41. end
  42. if isMacro = 1 then do
  43.   /* insure that message and messageline are on */
  44.   'extract messageLine into messageLineSetting'
  45.   'extract messages    into messagesSetting'
  46.   'set messages    on'
  47.   'set messageLine on'
  48. end
  49.  
  50. /*
  51.   Read and parse arguments
  52. */
  53. PARSE UPPER ARG wildCardFileName  '(' optionsUpper
  54.  
  55.  
  56. kDebug = 0     /* set to 1 for debug info */
  57. if pos("DEBUG", optionsUpper) > 0 then kDebug = 1
  58.  
  59. wildCardFileName = strip(wildCardFileName)
  60. if wildCardFileName = "" then
  61.   wildCardFileName = "*.CPP"
  62.  
  63. /*
  64.   Initialize constants
  65. */
  66. publicString = "public"
  67. procString   = "proc"
  68. extrnString  = "extrn"
  69. kStaticWord  = "static"
  70.  
  71.  
  72. rootDirectory      = directory()
  73. assemblerFile      = rootDirectory"\genprag$.asm"
  74. objectFile         = rootDirectory"\genprag$.obj"
  75. OutFile            = rootDirectory"\genprag$.out"
  76. pragmaFile         = rootDirectory"\genprag$.h"
  77. filteredPragmaFile = rootDirectory"\initprag.h"
  78.  
  79. InitSegment      = "InitSegment"
  80. TermSegment      = "TermSegment"
  81. StaticSegment    = "StaticSegment"
  82.  
  83. /*
  84.  check for file already in ring
  85. */
  86. if isMacro = 1 then do
  87.   'EXTRACT DOCLIST'
  88.   if doclist \= '' then
  89.      'EXTRACT DOCNUM INTO SAVEDOCNUM'
  90.   else
  91.      savedocnum = 0
  92.   do while doclist \= ''
  93.      parse var doclist docnum doclist
  94.      'GODOC DOCNUM 'docnum
  95.      if rc <= 1 then do
  96.        'EXTRACT NAME into currentDocName'
  97.        if translate(currentDocName) = translate(filteredPragmaFile) then
  98.           'qquit'
  99.      end
  100.   end
  101.   if savedocnum \= 0 then
  102.      'GODOC DOCNUM 'savedocnum
  103. end
  104.  
  105. if stream(pragmaFile,'C','QUERY EXIST')<>'' then
  106.    call osCmd '@DEL 'pragmaFile
  107.  
  108.  
  109. /*
  110.   Write a prolog to the output file
  111. */
  112. rc = lineOut(pragmaFile, "// Generated by "me )
  113. rc = lineOut(pragmaFile, "// Arguments were "wildCardFileName  )
  114. rc = lineOut(pragmaFile, " " )
  115.  
  116.  
  117. /*
  118.   Collect a list of the files to process
  119. */
  120. cppFiles. = 0
  121. if kDebug = 1 then
  122.   call sayErr 'wildCardFileName='wildCardFileName
  123. rc=SysFileTree(wildCardFileName,'cppFiles','FO','*****')
  124.  
  125. /*
  126.   Process each CPP file
  127. */
  128. do fileNumber=1 TO cppFiles.0
  129.   call refreshDisplay
  130.   call sayErr "Processing file "fileNumber" of "cppFiles.0" ("cppFiles.fileNumber")"
  131.   /* Erase the assembler file and create the next one */
  132.   if stream(assemblerFile,'C','QUERY EXIST')<>'' then
  133.      call osCmd '@DEL 'assemblerFile
  134.   iccOptions = "-c -Ft- -O+ -W2 -Q+ -Gm+ -Gd+"
  135.   if 0 \= osCmd( '@ICC' iccOptions '-Fa'assemblerFile '-Fo'objectFile  cppFiles.fileNumber' > 'outFile ) then do
  136.      call sayErr "ICC failed"
  137.      if isMacro = 1 then
  138.         'lx 'outFile
  139.      else
  140.         call osCmd 'type 'outFile
  141.      exit 1
  142.   end
  143.  
  144.   /*
  145.      Build a table of public symbols from the assembler file.
  146.   */
  147.   filePublics. = 0
  148.   call SysFileSearch publicString, assemblerFile, 'filePublics', 'C'
  149.   if kDebug = 1 then do
  150.      call sayErr "FilePublics.0 = "filePublics.0
  151.      call refreshDisplay
  152.   end
  153.   publicList. = 0
  154.   do j=1 to filePublics.0
  155.      filePublics.j = translate(filePublics.j, ' ', '09'x)   /* remove tabs */
  156.      parse var  filePublics.j publicKeyword function
  157.      if kDebug = 1 then
  158.        call sayErr "PUBLIC: " publicKeyword function
  159.      /* We want the statements of the form                        */
  160.      /* public  __functionName                                    */
  161.      /* but not segment declarations and such.                    */
  162.      if strip(publicKeyword) = publicString  then do
  163.         publicList.0 = publicList.0 + 1
  164.         currentPublic = publicList.0
  165.         publicList.currentPublic = strip(function)
  166.      end  /* if */
  167.   end  /* do */
  168.  
  169.  
  170.   /*
  171.      Build a table of procedures ("proc", both public & static).
  172.   */
  173.   fileProcs. = 0
  174.   call SysFileSearch procString, assemblerFile, 'fileProcs', 'C'
  175.   procList.  = 0
  176.   do j=1 to fileProcs.0
  177.      fileProcs.j = translate(fileProcs.j, ' ', '09'x)
  178.      parse value fileProcs.j with fileProcs.j ";" comment
  179.      /* The following logic attempts to eliminate lines that get
  180.         included that are not "proc" statements (e.g. lines with
  181.         words like "process").
  182.      */
  183.      if words(fileProcs.j) = 2 & word(fileProcs.j,2) = procString then do
  184.         procList.0 = procList.0 + 1
  185.         currentProc = procList.0
  186.         procList.currentProc = strip(word(fileProcs.j,1))
  187.         if kDebug = 1 then
  188.           call sayErr "PROC: "fileProcs.j
  189.      end  /* if */
  190.   end /* do */
  191.  
  192.   /*
  193.      Flag the functions in the procList as being PUBLIC or
  194.      STATIC (STATICS are in the procList but not the publicList).
  195.   */
  196.   staticsFound = 0
  197.   do j=1 to procList.0
  198.      found = 0
  199.      do k=1 to publicList.0 while found = 0
  200.         if procList.j = publicList.k then do
  201.            found = 1
  202.            procList.j.scope = publicString
  203.         end
  204.      end  /* do */
  205.      /* Not found in public list so must be a static */
  206.      if found = 0 then do
  207.        procList.j.scope = kStaticWord
  208.        staticsFound = 1
  209.      end /* if */
  210.   end /* do */
  211.  
  212.   /*
  213.      Determine the alloc_text pragmas for functions meeting
  214.      one of the criteria.
  215.   */
  216.   if staticsFound = 1 then do
  217.     /* Determine the File Name and write an #ifdef for it */
  218.     cppOffset = pos('.', cppFiles.fileNumber)
  219.     lastSlash = lastPos('\', cppFiles.fileNumber)
  220.     cppNameLength = cppOffset - lastSlash -1
  221.     cppFileName = substr(cppFiles.fileNumber, lastSlash+1, cppNameLength)
  222.     rc = lineOut(pragmaFile, "#ifdef _"||translate(cppFileName)||"_CPP_")
  223.  
  224.     /* Now dump out the segment definitions for Statics  */
  225.     do procNumber=1 to procList.0
  226.       if procList.procNumber.scope = kStaticWord then do
  227.          writePragma = 1
  228.          outBuffer = "#pragma alloc_text("
  229.          /* Do not write out Exception Functions because  */
  230.          /* they are in EH_CODE already.                  */
  231.          if pos("__dftdt", procList.procNumber) > 0   | ,
  232.             pos("__dftbdt", procList.procNumber) > 0  then
  233.            writePragma = 0
  234.          if pos("__dftct", procList.procNumber) > 0 then
  235.            outBuffer = outbuffer||StaticSegment
  236.          /* Write out Initialization functions */
  237.          else if pos("__sinit", procList.procNumber) > 0  then
  238.            outBuffer = outbuffer||InitSegment
  239.          /* Write out termination functions */
  240.          else if pos("__sterm", procList.procNumber) > 0 then
  241.            outBuffer = outbuffer||TermSegment
  242.          else
  243.            outBuffer = outbuffer||StaticSegment
  244.  
  245.          outBuffer = outBuffer||"," procList.procNumber||")"
  246.          if writePragma = 1 then
  247.            rc = lineOut(pragmaFile, outBuffer)
  248.       end
  249.     end /* do procNumber */
  250.  
  251.     rc = lineOut(pragmaFile, "#endif")
  252.     rc = lineOut(pragmaFile, "")
  253.   end /* do staticsExist */
  254. end /* do fileNumber */
  255. rc = stream(pragmaFile, 'C', 'close')
  256.  
  257. /*
  258.   Use CPPFILT on the pragma file
  259. */
  260. call oscmd '@CPPFILT /q' pragmaFile ' > ' filteredPragmaFile
  261.  
  262. /* cleanup temporary files */
  263. if kDebug = 0 then do
  264.   if stream(assemblerFile,'C','QUERY EXIST')<>'' then
  265.      call osCmd '@DEL 'assemblerFile
  266.   if stream(objectFile,'C','QUERY EXIST')<>'' then
  267.      call osCmd '@DEL 'objectFile
  268.   if stream(outFile,'C','QUERY EXIST')<>'' then
  269.      call osCmd '@DEL 'OutFile
  270.   if stream(pragmaFile,'C','QUERY EXIST')<>'' then
  271.      call osCmd '@DEL 'pragmaFile
  272. end
  273.  
  274. /* restore previous settings and view the results if a macro */
  275. if isMacro = 1 then do
  276.   'set messageLine 'messageLineSetting
  277.   'set messages    'messagesSetting
  278.   'lx 'filteredPragmaFile
  279. end
  280.  
  281. exit 0
  282.  
  283. /* Utility function to call a system function */
  284. oscmd:
  285.   parse arg theCmd
  286.  
  287.   if pos('@', theCmd) \= 1 | kDebug \= 0 then
  288.     call sayErr theCmd
  289.   if pos('@', theCmd) = 1 then
  290.     Address 'CMD' substr(theCmd, 2)
  291.   else
  292.     Address 'CMD' theCmd
  293.   return rc
  294.  
  295. /* Utility function to write error message    */
  296. sayErr:
  297. procedure expose isMacro
  298. parse arg theString
  299. if isMacro = 1 then
  300.    'msg 'theString
  301. else
  302.    say theString
  303. call refreshDisplay
  304. return
  305.  
  306. /* Utility function to update the display     */
  307. refreshDisplay:
  308. procedure expose isMacro
  309. if isMacro = 1 then
  310.    'sshow'
  311. return
  312.  
  313.