@@ -34,13 +34,19 @@ function META.New(tokens, code, config)
3434 config .system_include_paths = config .system_include_paths or {}
3535
3636 if config .add_standard_defines ~= false then
37+ -- Generate __DATE__ and __TIME__ at preprocessing time
38+ local date_str = os.date (" \" %b %d %Y\" " )
39+ local time_str = os.date (" \" %H:%M:%S\" " )
40+
3741 local standard_defines = {
3842 __STDC__ = 1 ,
3943 __STDC_VERSION__ = " 201710L" ,
4044 __STDC_HOSTED__ = 1 ,
4145 __GNUC__ = 4 ,
4246 __GNUC_MINOR__ = 2 ,
4347 __GNUC_PATCHLEVEL__ = 1 ,
48+ __DATE__ = date_str ,
49+ __TIME__ = time_str ,
4450 }
4551
4652 for name , value in pairs (standard_defines ) do
@@ -54,6 +60,7 @@ function META.New(tokens, code, config)
5460 self .conditional_stack = {} -- Track nested #if/#ifdef/#ifndef states
5561 self .position_stack = {} -- Track positions for directive token removal
5662 self .include_depth = 0 -- Track current include depth
63+ self .current_line = 1 -- Track current line number for __LINE__ macro
5764 -- Add predefined macros
5865 for name , value in pairs (config .defines ) do
5966 if type (value ) == " boolean" then
@@ -838,6 +845,49 @@ do -- #include directive
838845 return nil , " Include file not found: " .. filename
839846 end
840847
848+ function META :ReadError ()
849+ if not (self :IsToken (" #" ) and self :IsTokenValueOffset (" error" , 1 )) then
850+ return false
851+ end
852+
853+ self :PushPosition ()
854+ local hashtag = self :ExpectToken (" #" )
855+ local directive = self :ExpectTokenValue (" error" )
856+ local message_tokens = self :CaptureTokens ()
857+ local message = self :ToString (message_tokens , false ):gsub (" ^%s+" , " " ):gsub (" %s+$" , " " )
858+ self :RemoveDirectiveTokens ()
859+ error (" #error: " .. message )
860+ end
861+
862+ function META :ReadWarning ()
863+ if not (self :IsToken (" #" ) and self :IsTokenValueOffset (" warning" , 1 )) then
864+ return false
865+ end
866+
867+ self :PushPosition ()
868+ local hashtag = self :ExpectToken (" #" )
869+ local directive = self :ExpectTokenValue (" warning" )
870+ local message_tokens = self :CaptureTokens ()
871+ local message = self :ToString (message_tokens , false ):gsub (" ^%s+" , " " ):gsub (" %s+$" , " " )
872+ self :RemoveDirectiveTokens ()
873+ print (" #warning: " .. message )
874+ return true
875+ end
876+
877+ function META :ReadPragma ()
878+ if not (self :IsToken (" #" ) and self :IsTokenValueOffset (" pragma" , 1 )) then
879+ return false
880+ end
881+
882+ self :PushPosition ()
883+ local hashtag = self :ExpectToken (" #" )
884+ local directive = self :ExpectTokenValue (" pragma" )
885+ -- Capture and ignore the pragma content (implementation-specific)
886+ self :CaptureTokens ()
887+ self :RemoveDirectiveTokens ()
888+ return true
889+ end
890+
841891 function META :ReadInclude ()
842892 if not (self :IsToken (" #" ) and self :IsTokenValueOffset (" include" , 1 )) then
843893 return false
@@ -1292,6 +1342,24 @@ function META:ExpandMacro()
12921342 return self :HandleVAOPT ()
12931343 end
12941344
1345+ -- Special handling for __LINE__ and __FILE__
1346+ if tk .type == " letter" and tk :ValueEquals (" __LINE__" ) then
1347+ local line_token = self :NewToken (" number" , tostring (self .current_line ))
1348+ transfer_token_whitespace (tk :Copy (), {line_token }, false )
1349+ self :RemoveToken (self :GetPosition ())
1350+ self :AddTokens ({line_token })
1351+ return true
1352+ end
1353+
1354+ if tk .type == " letter" and tk :ValueEquals (" __FILE__" ) then
1355+ local filename = (self .Code and self .Code :GetName ()) or " unknown"
1356+ local file_token = self :NewToken (" string" , " \" " .. filename .. " \" " )
1357+ transfer_token_whitespace (tk :Copy (), {file_token }, false )
1358+ self :RemoveToken (self :GetPosition ())
1359+ self :AddTokens ({file_token })
1360+ return true
1361+ end
1362+
12951363 local def = self :GetDefinition (nil , 0 )
12961364
12971365 if not def then return false end
@@ -1364,9 +1432,22 @@ end
13641432
13651433function META :NextToken ()
13661434 if not self :GetDefinition (nil , 0 ) then
1435+ local prev_tk = self :GetToken ()
13671436 self :Advance (1 )
13681437 local tk = self :GetToken ()
13691438
1439+ -- Update line counter when we see newlines in whitespace
1440+ if prev_tk :HasWhitespace () then
1441+ for _ , ws in ipairs (prev_tk :GetWhitespace ()) do
1442+ local ws_str = ws :GetValueString ()
1443+ for i = 1 , # ws_str do
1444+ if ws_str :sub (i , i ) == " \n " then
1445+ self .current_line = self .current_line + 1
1446+ end
1447+ end
1448+ end
1449+ end
1450+
13701451 if tk .type == " end_of_file" then return false end
13711452
13721453 return true
@@ -1387,6 +1468,9 @@ function META:Parse()
13871468 self :ReadElif () or
13881469 self :ReadElse () or
13891470 self :ReadEndif () or
1471+ self :ReadError () or
1472+ self :ReadWarning () or
1473+ self :ReadPragma () or
13901474 self :ReadInclude () or
13911475 self :ExpandMacroCall () or
13921476 self :ExpandMacroConcatenation () or
0 commit comments