node/lib/metasm/metasm/preprocessor.rb
# applies a preprocessor macro
# parses arguments if needed
# macros are lazy
# fills tokens.expanded_from
# returns an array of tokens
applies a preprocessor macro
parses arguments if needed
macros are lazy
fills tokens.expanded_from
returns an array of tokens
applies a preprocessor macro parses arguments if needed macros are lazy fills tokens . expanded_from returns an array of tokens
def apply(lexer, name, args, list=nil)
			expfrom = name.expanded_from.to_a + [name]
			if args
				hargs = @args.zip(args).inject({}) { |h, (af, ar)| h.update af.raw => ar }
				if not varargs
					raise name, 'invalid argument count' if args.length != @args.length
				else
					raise name, 'invalid argument count' if args.length < @args.length
					virg = name.dup		
					virg.type = :punct
					virg.raw = ','
					va = args[@args.length..-1].map { |a| a + [virg.dup] }.flatten
					va.pop
					hargs['__VA_ARGS__'] = va
				end
			else
				hargs = {}
			end
			res = []
			b = @body.map { |t| t = t.dup ; t.expanded_from = expfrom ; t }
			while t = b.shift
				if a = hargs[t.raw]
					a = a.dup
					while at = a.shift
						margs = nil
						if at.type == :string and am = lexer.definition[at.raw] and not at.expanded_from.to_a.find { |ef| ef.raw == @name.raw } and
								((am.args and margs = Macro.parse_arglist(lexer, a)) or not am.args)
							toks = am.apply(lexer, at, margs, a)
							a = toks + a	
						else
							res << at.dup if not res.last or res.last.type != :space or at.type != :space
						end
					end
				elsif t.type == :punct and t.raw == '##'
					nil while t = b.shift and t.type == :space
					res.pop while res.last and res.last.type == :space
					if not a = hargs[t.raw]
						a = [t]
					end
					if varargs and t.raw == '__VA_ARGS__' and res.last and res.last.type == :punct and res.last.raw == ','
						if args.length == @args.length 
							res.pop
						else 
							res.concat a
						end
					else
						a = a[1..-1] if a.first and a.first.type == :space
						if not res.last or res.last.type != :string or not a.first or a.first.type != :string
							puts name.exception("cannot merge token #{res.last.raw} with #{a.first ? a.first.raw : 'nil'}").message if not a.first or (a.first.raw != '.' and res.last.raw != '.') if $VERBOSE
							res.concat a
						else
							res[-1] = res[-1].dup
							res.last.raw << a.first.raw
							res.concat a[1..-1]
						end
					end
				elsif args and t.type == :punct and t.raw == '#' 
					nil while t = b.shift and t.type == :space
					t.type = :quoted
					t.value = hargs[t.raw].map { |aa| aa.raw }.join
					t.value = t.value[1..-1] if t.value[0] == ?\ 	
					t.raw = t.value.inspect
					res << t
				else
					res << t
				end
			end
			res
		end
def apply ( lexer , name , args , list = nil ) expfrom = name . expanded_from . to_a + [ name ] if args hargs = @args . zip ( args ) . inject ( { } ) { | h , ( af , ar ) | h . update af . raw => ar } if not varargs raise name , 'invalid argument count' if args . length != @args . length else raise name , 'invalid argument count' if args . length < @args . length virg = name . dup virg . type = :punct virg . raw = ',' va = args [ @args . length .. - 1 ] . map { | a | a + [ virg . dup ] } . flatten va . pop hargs [ '__VA_ARGS__' ] = va end else hargs = { } end res = [ ] b = @body . map { | t | t = t . dup ; t . expanded_from = expfrom ; t } while t = b . shift if a = hargs [ t . raw ] a = a . dup while at = a . shift margs = nil if at . type == :string and am = lexer . definition [ at . raw ] and not at . expanded_from . to_a . find { | ef | ef . raw == @name . raw } and ( ( am . args and margs = Macro . parse_arglist ( lexer , a ) ) or not am . args ) toks = am . apply ( lexer , at , margs , a ) a = toks + a else res << at . dup if not res . last or res . last . type != :space or at . type != :space end end elsif t . type == :punct and t . raw == '##' nil while t = b . shift and t . type == :space res . pop while res . last and res . last . type == :space if not a = hargs [ t . raw ] a = [ t ] end if varargs and t . raw == '__VA_ARGS__' and res . last and res . last . type == :punct and res . last . raw == ',' if args . length == @args . length res . pop else res . concat a end else a = a [ 1 .. - 1 ] if a . first and a . first . type == :space if not res . last or res . last . type != :string or not a . first or a . first . type != :string puts name . exception ( "cannot merge token #{res.last.raw} with #{a.first ? a.first.raw : 'nil'}" ) . message if not a . first or ( a . first . raw != '.' and res . last . raw != '.' ) if $VERBOSE res . concat a else res [ - 1 ] = res [ - 1 ] . dup res . last . raw << a . first . raw res . concat a [ 1 .. - 1 ] end end elsif args and t . type == :punct and t . raw == '#' nil while t = b . shift and t . type == :space t . type = :quoted t . value = hargs [ t . raw ] . map { | aa | aa . raw } . join t . value = t . value [ 1 .. - 1 ] if t . value [ 0 ] == ?\ t . raw = t . value . inspect res << t else res << t end end res end
applies a preprocessor macro
parses arguments if needed
macros are lazy
fills tokens.expanded_from
returns an array of tokens
applies a preprocessor macro parses arguments if needed macros are lazy fills tokens . expanded_from returns an array of tokens
# hargs is a hash argname.raw => array of tokens # concat remaining args in __VA_ARGS__ # expand macros # reroll # the '##' operator: concat the next token to the last in body # pop last , if no vararg passed # XXX poof(1, 2,) != poof(1, 2) # allow merging with ',' without warning # map an arg to a qstring # delete leading space
lexer
name
args
list