November 24, 2020, 06:53:20 AM

Author Topic: [bb] Super-simple C-style preprocessor by Yasha [ 1+ years ago ]  (Read 629 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
Title : Super-simple C-style preprocessor
Author : Yasha
Posted : 1+ years ago

Description : This is the preprocessor I originally tried to force on top of my <a href="../Community/posts6473.html?topic=84763" target="_blank">failed QuakeC implementation[/url]. It's since found its way into my other projects, including <a href="../Community/posts17a0.html?topic=87642" target="_blank">Objective-B3D[/url]. It's not actually all that useful (no macros!), and nowadays many people (read: Java users) are opposed to this sort of thing altogether, but here it is if anyone wants it. Bear in mind that this doesn't include any way to preserve line numbering or file names (useful for error messages), which is why I've stopped using it.

(taken from the code below)
;Commands:
;   #define NAME CONSTANT - replace all occurences of NAME with CONSTANT. Cannot refer to other #defines
;   #undef NAME - remove a #defined constant so it isn't replaced any more
;   #if EXPRESSION - either compare a constant to another constant (literal or #defined) or assert that it's nonzero
;   #ifdef NAME - include the following block of code only if NAME has been #defined
;   #ifndef NAME - include the following block of code only if NAME has not been #defined
;   #elif EXPRESSION - short for ElseIf
;   #else - if the last check evaluated false, do this instead
;   #endif - mark the end of a conditional inclusion block. These are allowed to nest
;   #include FILE - copy the entire contents of the specified filename (quotemarks optional)
;   #option OPTION - does nothing: add language-relevant options here
;   #error ERR - issues error ERR via error handler. Best used with a condition check...!

;Notes:
;   - #define does not create macros, only simple substitution constants
;   - commands must be the first text on their line
;   - any text after a command will potentially be considered part of it, or at best ignored


Code :
Code: BlitzBasic
  1. ;General-purpose C-like directive processor
  2. ;==========================================
  3.  
  4.  
  5. ;Not very useful by itself, but you can plug it in to a code processor or script compiler easily
  6.  
  7.  
  8. ;Commands:
  9. ;       #define NAME CONSTANT - replace all occurences of NAME with CONSTANT. Cannot refer to other #defines
  10. ;       #undef NAME - remove a #defined constant so it isn't replaced any more
  11. ;       #if EXPRESSION - either compare a constant to another constant (literal or #defined) or assert that it's nonzero
  12. ;       #ifdef NAME - include the following block of code only if NAME has been #defined
  13. ;       #ifndef NAME - include the following block of code only if NAME has not been #defined
  14. ;       #elif EXPRESSION - short for ElseIf
  15. ;       #else - if the last check evaluated false, do this instead
  16. ;       #endif - mark the end of a conditional inclusion block. These are allowed to nest
  17. ;       #include FILE - copy the entire contents of the specified filename (quotemarks optional)
  18. ;       #option OPTION - does nothing: add language-relevant options here
  19. ;       #error ERR - issues error ERR via error handler. Best used with a condition check...!
  20.  
  21. ;Notes:
  22. ;       - #define does not create macros, only simple substitution constants
  23. ;       - commands must be the first text on their line
  24. ;       - any text after a command will potentially be considered part of it, or at best ignored
  25.  
  26.  
  27. ;Replace these with tokens that match your language
  28. Const PP_LINECOMMENT$ = "//"            ;Single-line comment
  29. Const PP_BLOCKCOMMENTSTART$ = "/*"      ;Start of block-comment
  30. Const PP_BLOCKCOMMENTEND$ = "*/"        ;End of block-comment
  31. Const PP_ESCAPECHR$ = ""                        ;Escape character (to allow " to appear in strings)
  32.  
  33. Type PP_Macro                   ;As defined with #define. No regular expressions, just cut and paste
  34.         Field tok$              ;Constant token to use in source
  35.         Field def$              ;Definition
  36. End Type
  37.  
  38. Function PP_Preprocess(inputFilename$,outputFilename$)          ;Loads the source from file and applies preprocessor commands
  39.         Local m.PP_Macro,n.PP_Macro,pos,ptr,i
  40.         Local com,sep,skip,debugout,srcline$,remain$
  41.         Local inquote,incomment,cfile,filelist=CreateBank(4)
  42.         Local sourceBank=CreateBank(4),iStack=CreateBank(0)
  43.        
  44.         cfile=ReadFile(inputFilename)
  45.         PokeInt(filelist,0,cfile)
  46.         Repeat
  47.                 srcline=ReadLine(cfile)
  48.                
  49.                 If Left(Trim(srcline),1)="#"
  50.                         srcline=Replace(srcline,Chr(9)," ")
  51.                         com=Instr(srcline,PP_BLOCKCOMMENTSTART)
  52.                         If com>0
  53.                                 remain=Right(srcline,Len(srcline)-(com-1))              ;Rescue comments with /* as otherwise there will be parse errors later
  54.                                
  55.                                 ResizeBank sourceBank,BankSize(sourceBank)+Len(remain)+2
  56.                                 For ptr=0 To Len(remain)-1
  57.                                         PokeByte sourceBank,pos+ptr,Asc(Mid(remain,ptr+1,1))
  58.                                 Next
  59.                                 PokeShort sourceBank,pos+ptr,$A0D               ;CR+LF - end of line
  60.                                 pos=pos+ptr+2
  61.                                
  62.                                 srcline=Left(srcline,com-1)
  63.                         EndIf
  64.                        
  65.                         com=Instr(srcline,PP_LINECOMMENT)
  66.                         If com>0 Then srcline=Left(srcline,com-1)
  67.                         srcline=Trim(srcline)+" "       ;Force control line to end in a space
  68.                        
  69.                         Select True
  70.                                 Case Lower(Left(srcline,8))="#define "                          ;Add a macro
  71.                                         If skip=0
  72.                                                 m=New PP_Macro
  73.                                                 srcline=Trim(Mid(srcline,8))
  74.                                                 sep=Instr(srcline," ")
  75.                                                
  76.                                                 If sep
  77.                                                         m       ok=Trim(Left(srcline,sep))
  78.                                                         mdef=Trim(Mid(srcline,sep+1))
  79.                                                 Else
  80.                                                         m       ok=srcline
  81.                                                         mdef=""
  82.                                                 EndIf
  83.                                                
  84.                                                 For n=Each PP_Macro
  85.                                                         If n<>m And m   ok=n    ok Then PP_Error("Token "+m     ok+" is already defined")
  86.                                                 Next
  87.                                         EndIf
  88.                                        
  89.                                 Case Lower(Left(srcline,7))="#undef "                           ;Remove a macro
  90.                                         If skip=0
  91.                                                 srcline=Trim(Mid(srcline,7))
  92.                                                 For m=Each PP_Macro
  93.                                                         If m    ok=srcline Then Delete m:Exit
  94.                                                 Next
  95.                                                 If m=Null Then PP_Error("token "+Chr(34)+srcline+Chr(34)+" does not exist")
  96.                                         EndIf
  97.                                        
  98.                                 Case Lower(Left(srcline,4))="#if "                                      ;Conditional compilation by value
  99.                                         srcline=Trim(Mid(srcline,4))
  100.                                         If skip=0
  101.                                                 ResizeBank iStack,BankSize(iStack)+1
  102.                                                 skip=skip+(Not(PP_EvalDirective(srcline)))
  103.                                                 PokeByte iStack,BankSize(iStack)-1,Not(skip)
  104.                                         Else
  105.                                                 skip=skip+1
  106.                                         EndIf
  107.                                        
  108.                                 Case Lower(Left(srcline,7))="#ifdef "                           ;Conditional compilation by definition
  109.                                         srcline=Trim(Mid(srcline,7))
  110.                                         If skip=0
  111.                                                 ResizeBank iStack,BankSize(iStack)+1
  112.                                                 skip=skip+1
  113.                                                 For m=Each PP_Macro
  114.                                                         If m    ok=srcline Then skip=skip-1:Exit
  115.                                                 Next
  116.                                                 PokeByte iStack,BankSize(iStack)-1,Not(skip)
  117.                                         Else
  118.                                                 skip=skip+1
  119.                                         EndIf
  120.                                        
  121.                                 Case Lower(Left(srcline,8))="#ifndef "                          ;Conditional lack of compilation by definition
  122.                                         srcline=Trim(Mid(srcline,8))
  123.                                         If skip=0
  124.                                                 ResizeBank iStack,BankSize(iStack)+1
  125.                                                 For m=Each PP_Macro
  126.                                                         If m    ok=srcline Then skip=skip+1:Exit
  127.                                                 Next
  128.                                                 PokeByte iStack,BankSize(iStack)-1,Not(skip)
  129.                                         Else
  130.                                                 skip=skip+1
  131.                                         EndIf
  132.                                        
  133.                                 Case Lower(Left(srcline,6))="#elif "                            ;Alternate condition check
  134.                                         If skip=1
  135.                                                 srcline=Trim(Mid(srcline,6))
  136.                                                 If PeekByte(iStack,BankSize(iStack)-1)=0        ;Only try if this #if level hasn't done anything yet
  137.                                                         If PP_EvalDirective(srcline)
  138.                                                                 PokeByte iStack,BankSize(iStack)-1,1
  139.                                                                 skip=0
  140.                                                         EndIf
  141.                                                 Else
  142.                                                         skip=1
  143.                                                 EndIf
  144.                                         EndIf
  145.                                        
  146.                                 Case Lower(Left(srcline,6))="#else "                            ;Default condition
  147.                                         If skip=1
  148.                                                 If PeekByte(iStack,BankSize(iStack)-1)=0 Then skip=0
  149.                                         ElseIf skip=0
  150.                                                 skip=1
  151.                                         EndIf
  152.                                        
  153.                                 Case Lower(Left(srcline,7))="#endif "                           ;End of conditional compilation block
  154.                                         If skip>0 Then skip=skip-1
  155.                                         If skip=0
  156.                                                 If BankSize(iStack) Then ResizeBank iStack,BankSize(iStack)-1
  157.                                         EndIf
  158.                                        
  159.                                 Case Lower(Left(srcline,9))="#include "                         ;Include files
  160.                                         If skip=0
  161.                                                 srcline=Trim(Mid(srcline,9))
  162.                                                 If Left(srcline,1)=Chr(34) And Right(srcline,1)=Chr(34) Then srcline=Mid(srcline,2,Len(srcline)-2)      ;Cut off quote marks
  163.                                                 cfile=ReadFile(srcline)
  164.                                                 If cfile=0 Then PP_Error "file "+Chr(34)+srcline+Chr(34)+" does not exist"
  165.                                                 ResizeBank(filelist,BankSize(filelist)+4)
  166.                                                 PokeInt filelist,BankSize(filelist)-4,cfile
  167.                                         EndIf
  168.                                        
  169.                                 Case Lower(Left(srcline,8))="#option "                          ;Set compilation options
  170.                                         If skip=0
  171.                                                 srcline=Trim(Mid(srcline,8))
  172.                                                 Select srcline
  173.                                                         ;Left empty for future expansion
  174.                                                         Default:PP_Error("unrecognised compiler option")
  175.                                                 End Select
  176.                                         EndIf
  177.                                        
  178.                                 Case Lower(Left(srcline,7))="#error "
  179.                                         If skip=0
  180.                                                 srcline=Trim(Mid(srcline,7))
  181.                                                 PP_Error(srcline)
  182.                                         EndIf
  183.                                        
  184.                                 Default
  185.                                         PP_Error("unrecognised preprocessor command: "+Chr(34)+srcline+Chr(34))
  186.                         End Select
  187.                 Else
  188.                         If skip=0
  189.                                 If First PP_Macro<>Null         ;Replace #defined tokens
  190.                                         inquote=0
  191.                                         For ptr=1 To Len(srcline)
  192.                                                 If Mid(srcline,ptr,2)=PP_LINECOMMENT Then Exit
  193.                                                 If Mid(srcline,ptr,1)=Chr(34)
  194.                                                         If inquote=0
  195.                                                                 inquote=True
  196.                                                         Else
  197.                                                                 If Mid(srcline,ptr-1,1)<>PP_ESCAPECHR Then inquote=False
  198.                                                         EndIf
  199.                                                 EndIf
  200.                                                 If Mid(srcline,ptr,2)=PP_BLOCKCOMMENTSTART Then incomment=True:ElseIf Mid(srcline,ptr,2)=PP_BLOCKCOMMENTEND Then incomment=False
  201.                                                 If inquote=False And incomment=False
  202.                                                         For m=Each PP_Macro
  203.                                                                 If ptr>1 Then i=Asc(Mid(srcline,ptr-1,1)):Else i=0
  204.                                                                 If Not((i>47 And i<58) Or (i>64 And i<91) Or i=95 Or (i>96 And i<123))
  205.                                                                         i=Asc(Mid(srcline,ptr+Len(m     ok),1))
  206.                                                                         If Not((i>47 And i<58) Or (i>64 And i<91) Or i=95 Or (i>96 And i<123))
  207.                                                                                 If Mid(srcline,ptr,Len(m        ok))=m  ok
  208.                                                                                         srcline=Left(srcline,ptr-1)+mdef+Right(srcline,Len(srcline)-(ptr-1)-Len(m       ok))
  209.                                                                                 EndIf
  210.                                                                         EndIf
  211.                                                                 EndIf
  212.                                                         Next
  213.                                                 EndIf
  214.                                         Next
  215.                                 EndIf
  216.                                
  217.                                 ResizeBank sourceBank,BankSize(sourceBank)+Len(srcline)+2
  218.                                 For ptr=0 To Len(srcline)-1
  219.                                         PokeByte sourceBank,pos+ptr,Asc(Mid(srcline,ptr+1,1))
  220.                                 Next
  221.                                 PokeShort sourceBank,pos+ptr,$A0D               ;CR+LF - end of line
  222.                                 pos=pos+ptr+2
  223.                         EndIf
  224.                 EndIf
  225.                
  226.                 If Eof(cfile)
  227.                         CloseFile cfile
  228.                         ResizeBank filelist,BankSize(filelist)-4
  229.                         If BankSize(filelist)=0 Then Exit:Else cfile=PeekInt(filelist,BankSize(filelist)-4)
  230.                 EndIf
  231.         Forever
  232.        
  233.         ;Dump out a copy of the source to be read by the tokeniser
  234.         debugout=WriteFile(outputFilename)
  235.         WriteBytes(sourceBank,debugout,0,BankSize(sourceBank))
  236.         CloseFile debugout
  237.        
  238.         FreeBank filelist               ;Tidy up
  239.         FreeBank sourceBank
  240.         FreeBank iStack
  241.         Delete Each PP_Macro
  242. End Function
  243.  
  244. Function PP_EvalDirective(directive$)   ;Evaluate an #if directive
  245.         Local lArg$,op$,rArg$,i,m.PP_Macro
  246.        
  247.         i=Instr(directive," ")
  248.         lArg=Trim(Left(directive,i))
  249.         directive=Trim(Mid(directive,i))
  250.        
  251.         i=Instr(directive," ")
  252.         op=Trim(Left(directive,i))
  253.         rArg=Trim(Mid(directive,i))
  254.        
  255.         For m=Each PP_Macro
  256.                 If m    ok=lArg Then lArg=mdef
  257.                 If m    ok=rArg Then rArg=mdef
  258.         Next
  259.        
  260.         Select op
  261.                 Case "=","=="           ;On tests for equality, strings will be compared directly so "6.0" != "6" - must be converted if floats are involved
  262.                         If Instr(lArg,".") Or Instr(rArg,".")
  263.                                 Return (Float(lArg) = Float(rArg))
  264.                         Else
  265.                                 Return lArg=rArg
  266.                         EndIf
  267.                        
  268.                 Case "<>","!="
  269.                         If Instr(lArg,".") Or Instr(rArg,".")
  270.                                 Return (Float(lArg) <> Float(rArg))
  271.                         Else
  272.                                 Return lArg <> rArg
  273.                         EndIf
  274.                        
  275.                 Case "<"                        ;On tests that imply numerical value, strings will be automagically converted!
  276.                         Return lArg < rArg
  277.                        
  278.                 Case ">"
  279.                         Return lArg > rArg
  280.                        
  281.                 Case "<="
  282.                         Return lArg <= rArg
  283.                        
  284.                 Case ">="
  285.                         Return lArg >= rArg
  286.                        
  287.                 Case ""
  288.                         Return lArg<>0
  289.                        
  290.         End Select
  291. End Function
  292.  
  293. Function PP_Error(errorMessage$)                ;Replace calls to this with your compiler's main error handler function
  294.         Print "ERROR: "+errorMessage
  295.         WaitKey:End
  296. End Function


Comments : none...

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal