| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  | ! Copyright (C) 2009 Doug Coleman. | 
					
						
							|  |  |  | ! See http://factorcode.org/license.txt for BSD license. | 
					
						
							| 
									
										
										
										
											2009-11-05 18:12:10 -05:00
										 |  |  | USING: sequences.parser io io.encodings.utf8 io.files | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  | io.streams.string kernel combinators accessors io.pathnames | 
					
						
							|  |  |  | fry sequences arrays locals namespaces io.directories | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  | assocs math splitting make unicode.categories | 
					
						
							| 
									
										
										
										
											2009-08-01 21:42:29 -04:00
										 |  |  | combinators.short-circuit c.lexer ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  | IN: c.preprocessor | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : initial-library-paths ( -- seq )
 | 
					
						
							|  |  |  |     V{ "/usr/include" } clone ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  | : initial-symbol-table ( -- hashtable )
 | 
					
						
							|  |  |  |     H{ | 
					
						
							|  |  |  |         { "__APPLE__" "" } | 
					
						
							|  |  |  |         { "__amd64__" "" } | 
					
						
							|  |  |  |         { "__x86_64__" "" } | 
					
						
							|  |  |  |     } clone ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  | TUPLE: preprocessor-state library-paths symbol-table | 
					
						
							|  |  |  | include-nesting include-nesting-max processing-disabled? | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  | ifdef-nesting warnings errors | 
					
						
							|  |  |  | pragmas | 
					
						
							|  |  |  | include-nexts | 
					
						
							|  |  |  | ifs elifs elses ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : <preprocessor-state> ( -- preprocessor-state )
 | 
					
						
							|  |  |  |     preprocessor-state new
 | 
					
						
							|  |  |  |         initial-library-paths >>library-paths | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  |         initial-symbol-table >>symbol-table | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |         0 >>include-nesting | 
					
						
							|  |  |  |         200 >>include-nesting-max | 
					
						
							|  |  |  |         0 >>ifdef-nesting | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  |         V{ } clone >>warnings | 
					
						
							|  |  |  |         V{ } clone >>errors | 
					
						
							|  |  |  |         V{ } clone >>pragmas | 
					
						
							|  |  |  |         V{ } clone >>include-nexts | 
					
						
							|  |  |  |         V{ } clone >>ifs | 
					
						
							|  |  |  |         V{ } clone >>elifs | 
					
						
							|  |  |  |         V{ } clone >>elses ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | DEFER: preprocess-file | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | ERROR: unknown-c-preprocessor sequence-parser name ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | ERROR: bad-include-line line ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ERROR: header-file-missing path ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :: read-standard-include ( preprocessor-state path -- )
 | 
					
						
							|  |  |  |     preprocessor-state dup library-paths>> | 
					
						
							|  |  |  |     [ path append-path exists? ] find nip
 | 
					
						
							|  |  |  |     [ | 
					
						
							|  |  |  |         dup [ | 
					
						
							|  |  |  |             path append-path | 
					
						
							|  |  |  |             preprocess-file | 
					
						
							|  |  |  |         ] with-directory | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         ! path header-file-missing | 
					
						
							|  |  |  |         drop
 | 
					
						
							|  |  |  |     ] if* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :: read-local-include ( preprocessor-state path -- )
 | 
					
						
							|  |  |  |     current-directory get path append-path dup :> full-path | 
					
						
							|  |  |  |     dup exists? [ | 
					
						
							|  |  |  |         [ preprocessor-state ] dip preprocess-file | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         ! full-path header-file-missing | 
					
						
							|  |  |  |         drop
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : skip-whitespace/comments ( sequence-parser -- sequence-parser )
 | 
					
						
							|  |  |  |     skip-whitespace | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         { [ dup take-c-comment ] [ skip-whitespace/comments ] } | 
					
						
							|  |  |  |         { [ dup take-c++-comment ] [ skip-whitespace/comments ] } | 
					
						
							|  |  |  |         [ ] | 
					
						
							|  |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : handle-include ( preprocessor-state sequence-parser -- )
 | 
					
						
							|  |  |  |     skip-whitespace/comments advance dup previous { | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |         { CHAR: < [ CHAR: > take-until-object read-standard-include ] } | 
					
						
							|  |  |  |         { CHAR: " [ CHAR: " take-until-object read-local-include ] } | 
					
						
							|  |  |  |         [ bad-include-line ] | 
					
						
							|  |  |  |     } case ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : (readlns) ( -- )
 | 
					
						
							|  |  |  |     readln "\\" ?tail [ , ] dip [ (readlns) ] when ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : readlns ( -- string ) [ (readlns) ] { } make concat ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : take-define-identifier ( sequence-parser -- string )
 | 
					
						
							|  |  |  |     skip-whitespace/comments | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  |     [ current { [ blank? ] [ CHAR: ( = ] } 1|| ] take-until ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-05 16:34:31 -05:00
										 |  |  | :: handle-define ( preprocessor-state sequence-parser -- )
 | 
					
						
							|  |  |  |     sequence-parser take-define-identifier :> ident | 
					
						
							|  |  |  |     sequence-parser skip-whitespace/comments take-rest :> def | 
					
						
							|  |  |  |     def "\\" ?tail [ readlns append ] when :> def | 
					
						
							|  |  |  |     def ident preprocessor-state symbol-table>> set-at ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-undef ( preprocessor-state sequence-parser -- )
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |     take-token swap symbol-table>> delete-at ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-ifdef ( preprocessor-state sequence-parser -- )
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |     [ [ 1 + ] change-ifdef-nesting ] dip
 | 
					
						
							|  |  |  |     take-token over symbol-table>> key?
 | 
					
						
							|  |  |  |     [ drop ] [ t >>processing-disabled? drop ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-ifndef ( preprocessor-state sequence-parser -- )
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |     [ [ 1 + ] change-ifdef-nesting ] dip
 | 
					
						
							|  |  |  |     take-token over symbol-table>> key?
 | 
					
						
							|  |  |  |     [ t >>processing-disabled? drop ] | 
					
						
							|  |  |  |     [ drop ] if ;  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-endif ( preprocessor-state sequence-parser -- )
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |     drop [ 1 - ] change-ifdef-nesting drop ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-if ( preprocessor-state sequence-parser -- )
 | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  |     [ [ 1 + ] change-ifdef-nesting ] dip
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  |     skip-whitespace/comments take-rest swap ifs>> push ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-elif ( preprocessor-state sequence-parser -- )
 | 
					
						
							|  |  |  |     skip-whitespace/comments take-rest swap elifs>> push ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-else ( preprocessor-state sequence-parser -- )
 | 
					
						
							|  |  |  |     skip-whitespace/comments take-rest swap elses>> push ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-pragma ( preprocessor-state sequence-parser -- )
 | 
					
						
							|  |  |  |     skip-whitespace/comments take-rest swap pragmas>> push ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-include-next ( preprocessor-state sequence-parser -- )
 | 
					
						
							|  |  |  |     skip-whitespace/comments take-rest swap include-nexts>> push ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-error ( preprocessor-state sequence-parser -- )
 | 
					
						
							|  |  |  |     skip-whitespace/comments take-rest swap errors>> push ;
 | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  |     ! nip take-rest throw ; | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : handle-warning ( preprocessor-state sequence-parser -- )
 | 
					
						
							|  |  |  |     skip-whitespace/comments | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |     take-rest swap warnings>> push ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : parse-directive ( preprocessor-state sequence-parser string -- )
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |     { | 
					
						
							|  |  |  |         { "warning" [ handle-warning ] } | 
					
						
							|  |  |  |         { "error" [ handle-error ] } | 
					
						
							|  |  |  |         { "include" [ handle-include ] } | 
					
						
							|  |  |  |         { "define" [ handle-define ] } | 
					
						
							|  |  |  |         { "undef" [ handle-undef ] } | 
					
						
							|  |  |  |         { "ifdef" [ handle-ifdef ] } | 
					
						
							|  |  |  |         { "ifndef" [ handle-ifndef ] } | 
					
						
							|  |  |  |         { "endif" [ handle-endif ] } | 
					
						
							| 
									
										
										
										
											2009-04-02 12:39:18 -04:00
										 |  |  |         { "if" [ handle-if ] } | 
					
						
							|  |  |  |         { "elif" [ handle-elif ] } | 
					
						
							|  |  |  |         { "else" [ handle-else ] } | 
					
						
							|  |  |  |         { "pragma" [ handle-pragma ] } | 
					
						
							|  |  |  |         { "include_next" [ handle-include-next ] } | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |         [ unknown-c-preprocessor ] | 
					
						
							|  |  |  |     } case ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : parse-directive-line ( preprocessor-state sequence-parser -- )
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |     advance dup take-token | 
					
						
							|  |  |  |     pick processing-disabled?>> [ | 
					
						
							|  |  |  |         "endif" = [ | 
					
						
							|  |  |  |             drop f >>processing-disabled? | 
					
						
							|  |  |  |             [ 1 - ] change-ifdef-nesting | 
					
						
							|  |  |  |             drop
 | 
					
						
							|  |  |  |          ] [ 2drop ] if
 | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         parse-directive | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  | : preprocess-line ( preprocessor-state sequence-parser -- )
 | 
					
						
							|  |  |  |     skip-whitespace/comments dup current CHAR: # =
 | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |     [ parse-directive-line ] | 
					
						
							|  |  |  |     [ swap processing-disabled?>> [ drop ] [ write-full nl ] if ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : preprocess-lines ( preprocessor-state -- )
 | 
					
						
							|  |  |  |     readln  | 
					
						
							| 
									
										
										
										
											2009-04-10 18:50:05 -04:00
										 |  |  |     [ <sequence-parser> [ preprocess-line ] [ drop preprocess-lines ] 2bi ] | 
					
						
							| 
									
										
										
										
											2009-04-02 02:17:36 -04:00
										 |  |  |     [ drop ] if* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ERROR: include-nested-too-deeply ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : check-nesting ( preprocessor-state -- preprocessor-state )
 | 
					
						
							|  |  |  |     [ 1 + ] change-include-nesting | 
					
						
							|  |  |  |     dup [ include-nesting>> ] [ include-nesting-max>> ] bi > [ | 
					
						
							|  |  |  |         include-nested-too-deeply | 
					
						
							|  |  |  |     ] when ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : preprocess-file ( preprocessor-state path -- )
 | 
					
						
							|  |  |  |     [ check-nesting ] dip
 | 
					
						
							|  |  |  |     [ utf8 [ preprocess-lines ] with-file-reader ] | 
					
						
							|  |  |  |     [ drop [ 1 - ] change-include-nesting drop ] 2bi ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : start-preprocess-file ( path -- preprocessor-state string )
 | 
					
						
							|  |  |  |     dup parent-directory [ | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             [ <preprocessor-state> dup ] dip preprocess-file | 
					
						
							|  |  |  |         ] with-string-writer | 
					
						
							|  |  |  |     ] with-directory ;
 |