TheM4MacroProcessor BrianW.Kernighan DennisM.Ritchie ABSTRACT M4isamacroprocessoravailableonUNIX◯randGCOS.Itsprimaryuse hasbeenasafrontendforRatforforthosecaseswhereparameterlessmacrosare notadequatelypowerful.IthasalsobeenusedforlanguagesasdisparateasC andCobol.M4isparticularlysuitedforfunctionallanguageslikeFortran,PL/I andCsincemacrosarespecifiedinafunctionalnotation. M4providesfeaturesseldomfoundeveninmuchlargermacroprocessors, including •arguments •conditiontesting •arithmeticcapabilities •stringandsubstringfunctions •filemanipulation Thispaperisauser’smanualforM4. July1,1977 TheM4MacroProcessor BrianW.Kernighan DennisM.Ritchie Introduction Amacroprocessorisausefulwayto enhanceaprogramminglanguage,tomakeit morepalatableormorereadable,ortotailor ittoaparticularapplication.The#define statementinCandtheanalogousdefinein Ratforareexamplesofthebasicfacilityprovidedbyanymacroprocessor—replacement oftextbyothertext. TheM4macroprocessorisanextension ofamacroprocessorcalledM3whichwas writtenbyD.M.RitchiefortheAP-3mini-computer;M3wasinturnbasedonamacro processorimplementedfor[1].Readersunfamiliarwiththebasicideasofmacroprocessingmaywishtoreadsomeofthediscussion there. M4isasuitablefrontendforRatfor andC,andhasalsobeenusedsuccessfully withCobol.Besidesthestraightforward replacementofonestringoftextbyanother, itprovidesmacroswitharguments,conditionalmacroexpansion,arithmetic,file manipulation,andsomespecializedstring processingfunctions. ThebasicoperationofM4istocopyits inputtoitsoutput.Astheinputisread, however,eachalphanumeric‘‘token’’(thatis, stringoflettersanddigits)ischecked.Ifitis thenameofamacro,thenthenameofthe macroisreplacedbyitsdefiningtext,andthe resultingstringispushedbackontotheinput toberescanned.Macrosmaybecalledwith arguments,inwhichcasetheargumentsare collectedandsubstitutedintotherightplaces inthedefiningtextbeforeitisrescanned. M4providesacollectionofabout twentybuilt-inmacroswhichperformvarious usefuloperations;inaddition,theusercan definenewmacros.Built-insanduser-defined macrosworkexactlythesameway,except thatsomeofthebuilt-inmacroshaveside effectsonthestateoftheprocess.

Usage OnUNIX,use m4[files] Eachargumentfileisprocessedinorder;if therearenoarguments,orifanargumentis ` −’,thestandardinputisreadatthatpoint. Theprocessedtextiswrittenonthestandard output,whichmaybecapturedforsubsequentprocessingwith m4[files]>outputfile OnGCOS,usageisidentical,buttheprogram iscalled./m4. DefiningMacros Theprimarybuilt-infunctionofM4is define,whichisusedtodefinenewmacros. Theinput define(name,stuff) causesthestringnametobedefinedas stuff.Allsubsequentoccurrencesofname willbereplacedbystuff.namemustbe alphanumericandmustbeginwithaletter (theunderscorecountsasaletter).stuffis anytextthatcontainsbalancedparentheses; itmaystretchovermultiplelines. Thus,asatypicalexample, define(N,100) ... if(i>N) definesNtobe100,andusesthis` ` symbolic constant’’inalaterifstatement. Theleftparenthesismustimmediately followtheworddefine,tosignalthatdefine hasarguments.Ifamacroorbuilt-innameis notfollowedimmediatelyby` (’,itisassumed tohavenoarguments.Thisisthesituation forNabove;itisactuallyamacrowithno arguments,andthuswhenitisusedthere needbeno(...)followingit.

-2-Youshouldalsonoticethatamacro nameisonlyrecognizedassuchifitappears surroundedbynon-alphanumerics.Forexam-ple,in define(N,100) ... if(NNN>100) thevariableNNNisabsolutelyunrelatedto thedefinedmacroN,eventhoughitcontains alotofN’s. Thingsmaybedefinedintermsofother things.Forexample, define(N,100) define(M,N) definesbothMandNtobe100. WhathappensifNisredefined?Or,to sayitanotherway,isMdefinedasNoras 100?InM4,thelatteristrue—Mis100, soevenifNsubsequentlychanges,Mdoes not. ThisbehaviorarisesbecauseM4 expandsmacronamesintotheirdefiningtext assoonasitpossiblycan.Here,thatmeans thatwhenthestringNisseenastheargumentsofdefinearebeingcollected,itis immediatelyreplacedby100;it’sjustasif youhadsaid define(M,100) inthefirstplace. Ifthisisn’twhatyoureallywant,there aretwowaysoutofit.Thefirst,whichis specifictothissituation,istointerchangethe orderofthedefinitions: define(M,N) define(N,100) NowMisdefinedtobethestringN,so whenyouaskforMlater,you’llalwaysget thevalueofNatthattime(becausetheM willbereplacedbyNwhichwillbereplaced by100). Quoting Themoregeneralsolutionistodelay theexpansionoftheargumentsofdefineby quotingthem.Anytextsurroundedbythe singlequotes` and´ isnotexpandedimmediately,buthasthequotesstrippedoff.If yousay define(N,100) define(M,` N´ ) thequotesaroundtheNarestrippedoffas theargumentisbeingcollected,butthey haveservedtheirpurpose,andMisdefined asthestringN,not100.Thegeneralruleis thatM4alwaysstripsoffonelevelofsingle quoteswheneveritevaluatessomething.This istrueevenoutsideofmacros.Ifyouwant theworddefinetoappearintheoutput,you havetoquoteitintheinput,asin ` define´ =1; Asanotherinstanceofthesamething, whichisabitmoresurprising,consider redefiningN: define(N,100) ... define(N,200) Perhapsregrettably,theNintheseconddefinitionisevaluatedassoonasit’sseen;that is,itisreplacedby100,soit’sasifyouhad written define(100,200) ThisstatementisignoredbyM4,sinceyou canonlydefinethingsthatlooklikenames, butitobviouslydoesn’thavetheeffectyou wanted.ToreallyredefineN,youmustdelay theevaluationbyquoting: define(N,100) ... define(` N´ ,200) InM4,itisoftenwisetoquotethefirstargumentofamacro. If` and´ arenotconvenientforsome reason,thequotecharacterscanbechanged withthebuilt-inchangequote: changequote([,]) makesthenewquotecharacterstheleftand rightbrackets.Youcanrestoretheoriginal characterswithjust changequote Therearetwoadditionalbuilt-ins relatedtodefine.undefineremovesthedefinitionofsomemacroorbuilt-in: undefine(` N´ ) removesthedefinitionofN.(Whyarethe -3-quotesabsolutelynecessary?)Built-inscan beremovedwithundefine,asin undefine(` define´ ) butonceyouremoveone,youcanneverget itback. Thebuilt-inifdefprovidesawayto determineifamacroiscurrentlydefined.In particular,M4haspre-definedthenames unixandgcosonthecorrespondingsystems, soyoucantellwhichoneyou’reusing: ifdef(` unix´ ,` define(wordsize,16)´ ) ifdef(` gcos´ ,` define(wordsize,36)´ ) makesadefinitionappropriatefortheparticularmachine.Don’tforgetthequotes! ifdefactuallypermitsthreearguments; ifthenameisundefined,thevalueofifdefis thenthethirdargument,asin ifdef(` unix´ ,onUNIX,notonUNIX) Arguments Sofarwehavediscussedthesimplest formofmacroprocessing—replacingone stringbyanother(fixed)string.User-defined macrosmayalsohavearguments,sodifferent invocationscanhavedifferentresults.Within thereplacementtextforamacro(thesecond argumentofitsdefine)anyoccurrenceof$n willbereplacedbythenthargumentwhen themacroisactuallyused.Thus,themacro bump,definedas define(bump,$1=$1+1) generatescodetoincrementitsargumentby 1: bump(x) is x=x+1 Amacrocanhaveasmanyarguments asyouwant,butonlythefirstnineareaccessible,through$1to$9.(Themacroname itselfis$0,althoughthatislesscommonly used.)Argumentsthatarenotsuppliedare replacedbynullstrings,sowecandefinea macrocatwhichsimplyconcatenatesits arguments,likethis: define(cat,$1$2$3$4$5$6$7$8$9) Thus cat(x,y,z) isequivalentto xyz $4through$9arenull,sincenocorrespondingargumentswereprovided. Leadingunquotedblanks,tabs,ornewlinesthatoccurduringargumentcollection arediscarded.Allotherwhitespaceis retained.Thus define(a,bc) definesatobebc. Argumentsareseparatedbycommas, butparenthesesarecountedproperly,soa comma` ` protected’’byparenthesesdoesnot terminateanargument.Thatis,in define(a,(b,c)) thereareonlytwoarguments;thesecondis literally(b,c).Andofcourseabarecomma orparenthesiscanbeinsertedbyquotingit. ArithmeticBuilt-ins M4providestwobuilt-infunctionsfor doingarithmeticonintegers(only).Thesimplestisincr,whichincrementsitsnumeric argumentby1.Thustohandlethecommon programmingsituationwhereyouwanta variabletobedefinedas` ` onemorethanN’’, write define(N,100) define(N1,` incr(N)´ ) ThenN1isdefinedasonemorethanthecurrentvalueofN. Themoregeneralmechanismforarithmeticisabuilt-incalledeval,whichiscapa-bleofarbitraryarithmeticonintegers.It providestheoperators(indecreasingorderof precedence) unary+and− ∗∗orˆ (exponentiation) ∗/%(modulus) +− ==!=<<=>>= !(not) &or&&(logicaland) |or||(logicalor) Parenthesesmaybeusedtogroupoperations whereneeded.Alltheoperandsofanexpressiongiventoevalmustultimatelybe -4-numeric.Thenumericvalueofatruerela-tion(like1>0)is1,andfalseis0.Thepreci-sioninevalis32bitsonUNIXand36bitson GCOS. Asasimpleexample,supposewewant Mtobe2∗∗N+1.Then define(N,3) define(M,` eval(2∗∗N+1)´ ) Asamatterofprinciple,itisadvisableto quotethedefiningtextforamacrounlessit isverysimpleindeed(sayjustanumber);it usuallygivestheresultyouwant,andisa goodhabittogetinto. FileManipulation Youcanincludeanewfileintheinput atanytimebythebuilt-infunctioninclude: include(filename) insertsthecontentsoffilenameinplaceof theincludecommand.Thecontentsofthe fileisoftenasetofdefinitions.Thevalueof include(thatis,itsreplacementtext)isthe contentsofthefile;thiscanbecapturedin definitions,etc. Itisafatalerrorifthefilenamedin includecannotbeaccessed.Togetsome controloverthissituation,thealternateform sincludecanbeused;sinclude(` ` silent include’’)saysnothingandcontinuesifit can’taccessthefile. Itisalsopossibletodiverttheoutput ofM4totemporaryfilesduringprocessing, andoutputthecollectedmaterialuponcommand.M4maintainsnineofthesediversions, numbered1through9.Ifyousay divert(n) allsubsequentoutputisputontotheendofa temporaryfilereferredtoasn.Divertingto thisfileisstoppedbyanotherdivertcommand;inparticular,divertordivert(0) resumesthenormaloutputprocess. Divertedtextisnormallyoutputallat onceattheendofprocessing,withthediversionsoutputinnumericorder.Itispossible, however,tobringbackdiversionsatany time,thatis,toappendthemtothecurrent diversion. undivert bringsbackalldiversionsinnumericorder, andundivertwithargumentsbringsback theselecteddiversionsintheordergiven. Theactofundivertingdiscardsthediverted stuff,asdoesdivertingintoadiversionwhose numberisnotbetween0and9inclusive. Thevalueofundivertisnotthe divertedstuff.Furthermore,thediverted materialisnotrescannedformacros. Thebuilt-indivnumreturnsthe numberofthecurrentlyactivediversion. Thisiszeroduringnormalprocessing. SystemCommand Youcanrunanyprograminthelocal operatingsystemwiththesyscmdbuilt-in. Forexample, syscmd(date) onUNIXrunsthedatecommand.Normally syscmdwouldbeusedtocreateafilefora subsequentinclude. Tofacilitatemakinguniquefilenames, thebuilt-inmaketempisprovided,with specificationsidenticaltothesystemfunction mktemp:astringofXXXXXintheargument isreplacedbytheprocessidofthecurrent process. Conditionals Thereisabuilt-incalledifelsewhich enablesyoutoperformarbitraryconditional testing.Inthesimplestform, ifelse(a,b,c,d) comparesthetwostringsaandb.Ifthese areidentical,ifelsereturnsthestringc;otherwiseitreturnsd.Thuswemightdefinea macrocalledcomparewhichcomparestwo stringsandreturns` ` yes’’or` ` no’’ifthey arethesameordifferent. define(compare,` ifelse($1,$2,yes,no)´ ) Notethequotes,whichpreventtoo-early evaluationofifelse. Ifthefourthargumentismissing,itis treatedasempty. ifelsecanactuallyhaveanynumberof arguments,andthusprovidesalimitedform ofmulti-waydecisioncapability.Intheinput ifelse(a,b,c,d,e,f,g) ifthestringamatchesthestringb,theresult -5-isc.Otherwise,ifdisthesamease,the resultisf.Otherwisetheresultisg.Ifthe finalargumentisomitted,theresultisnull, so ifelse(a,b,c) iscifamatchesb,andnullotherwise. StringManipulation Thebuilt-inlenreturnsthelengthof thestringthatmakesupitsargument.Thus len(abcdef) is6,andlen((a,b))is5. Thebuilt-insubstrcanbeusedtopro-ducesubstringsofstrings.substr(s,i,n) returnsthesubstringofsthatstartsatthe ithposition(originzero),andisncharacters long.Ifnisomitted,therestofthestringis returned,so substr(` nowisthetime´ ,1) is owisthetime Ifiornareoutofrange,varioussensible thingshappen. index(s1,s2)returnstheindex(position)ins1wherethestrings2occurs,or−1 ifitdoesn’toccur.Aswithsubstr,theoriginforstringsis0. Thebuilt-intranslitperformscharac-tertransliteration. translit(s,f,t) modifiessbyreplacinganycharacterfound infbythecorrespondingcharacteroft. Thatis, translit(s,aeiou,12345) replacesthevowelsbythecorrespondingdigits.Iftisshorterthanf,characterswhich don’thaveanentryintaredeleted;asalimitingcase,iftisnotpresentatall,characters fromfaredeletedfroms.So translit(s,aeiou) deletesvowelsfroms. Thereisalsoabuilt-incalleddnlwhich deletesallcharactersthatfollowituptoand includingthenextnewline;itisusefulmainly forthrowingawayemptylinesthatotherwise tendtoclutterupM4output.Forexample, ifyousay define(N,100) define(M,200) define(L,300) thenewlineattheendofeachlineisnotpart ofthedefinition,soitiscopiedintotheoutput,whereitmaynotbewanted.Ifyouadd dnltoeachoftheselines,thenewlineswill disappear. Anotherwaytoachievethis,duetoJ. E.Weythman,is divert(−1) define(...) ... divert Printing Thebuilt-inerrprintwritesitsargu-mentsoutonthestandarderrorfile.Thus youcansay errprint(` fatalerror´ ) dumpdefisadebuggingaidwhich dumpsthecurrentdefinitionsofdefined terms.Iftherearenoarguments,youget everything;otherwiseyougettheonesyou nameasarguments.Don’tforgettoquote thenames! SummaryofBuilt-ins Eachentryisprecededbythepage numberwhereitisdescribed.

-6-3changequote(L,R) 1define(name,replacement) 4divert(number) 4divnum 5dnl 5dumpdef(` name´ ,` name´ ,...) 5errprint(s,s,...) 4eval(numericexpression) 3ifdef(` name´ ,thisiftrue,thisiffalse) 5ifelse(a,b,c,d) 4include(file) 3incr(number) 5index(s1,s2) 5len(string) 4maketemp(...XXXXX...) 4sinclude(file) 5substr(string,position,number) 4syscmd(s) 5translit(str,from,to) 3undefine(` name´ ) 4undivert(number,number,...) Acknowledgements WeareindebtedtoRickBecker,John Chambers,DougMcIlroy,andespeciallyJim Weythman,whosepioneeringuseofM4has ledtoseveralvaluableimprovements.Weare alsodeeplygratefultoWeythmanforseveral substantialcontributionstothecode. References [1]B.W.KernighanandP.J.Plauger, SoftwareTools,Addison-Wesley,Inc., 1976.