#! /usr/bin/env -S awk -f 'csmap.awk' BEGIN { stage1 = 1 depth = 0 __nvlen = 0 fileCount = 0 # Last stylesheet is also used for replacement ARGV[ARGC] = ARGV[ARGC - 1] ARGC++ } FNR == 1 { fileCount++ } # Do substitution on last file stage1 && fileCount == ARGC - 1 { stage1 = 0 stage2 = 1 depth = 0 macroNameOnly = 0 # Do substitutions inside definitions for (name in macros) { for (subname in macros) { gsub(subname, macros[subname], macros[name]) } } fileCount = 0 } # Comments (experimental) { sub(/[[:blank:]]*\/\/.*$/, "") } # # Stage 1 # Gather definitions # # function printNQ() { # print "All in nameQueue:" # for (ind in nameQueue) { # print "[" ind "] " nameQueue[ind] " | " nameClose[nameQueue[ind]] # } # } # # stage1 { # print "" # print $0 # print "Depth: " depth # printNQ() # } stage1 && macroNameOnly { # Skip blank lines if ($0 ~ /^[[:blank:]]*$/) { next } macroNameOnly = 0 # We had a name, blank lines, and now the beginning of line has "{" # There is a definition if (sub(/^[[:blank:]]*\{/, "") > 0) { depth++ } # The name was not starting a definition else { namevec_Pop() # Since the line didn't start a new definition, we need to add it # "back" verbatim to the current definition(s) for (ind in __nvnames) { macros[namevec_At(ind)] = macros[namevec_At(ind)] ORS macroNameLine } } } stage1 && /<[^>]*>[[:blank:]]*\{/ { # There is a definition namevec_Push() depth++ # Remove definition start sub(/^[^{]*{[[:blank:]]*/, "") } stage1 && /<[^>]*>/ { removeLeadingTabulation() # Start searching for a potential opening brace macroNameOnly = 1 macroNameLine = $0 namevec_Push() next } stage1 && depth >= 1 { depth += gsub("{", "{") - gsub("}", "}") removeLeadingTabulation() skipORS = 0 if (depth <= namevec_TopDepth()) { # Remove macro closing braces for (i = namevec_TopDepth() - depth; i >= 0; i--) { sub(/}/, "") } skipORS = 1 } # Add line to definition and parent definitions for (ind in __nvnames) { if (length(macros[namevec_At(ind)]) != 0 && !skipORS) { macros[namevec_At(ind)] = macros[namevec_At(ind)] ORS } macros[namevec_At(ind)] = macros[namevec_At(ind)] $0 } while (namevec_Length() > 0 && depth <= namevec_TopDepth()) { namevec_Pop() } next } function removeLeadingTabulation() { # Remove leading tabulation when inside macro definition for (i = namevec_Length(); i > 0; i--) { sub(/^ /, "") } } # # Stage 2 # Do substitution # # Skip over definitions stage2 && depth >= 1 { depth += gsub("{", "{") - gsub("}", "}") next } stage2 && macroNameOnly { # Skip over blank lines if ($0 ~ /^[[:blank:]]*$/) { next } macroNameOnly = 0 # If is definition if ($0 ~ /^[[:blank:]]*\{/) { depth = gsub("{", "{") - gsub("}", "}") macroName = "" next } # Do substitution else { print macros[macroName] macroName = "" } } stage2 && /^[[:blank:]]*<[^>]*>/ { # If we found a definition if ($0 ~ "{") { macroName = "" depth = gsub("{", "{") - gsub("}", "}") next } # If there isn't anything nonblank after the macro name then it might # be the name of a potential definition, with a "{" on another line else if (match($0, /<[^>]*>[[:blank:]]*[^[:blank:]]/) == 0) { match($0, /<[^>]*>/) macroName = substr($0, RSTART, RLENGTH) macroNameOnly = 1 next } } # Outside definition stage2 && depth == 0 { # Do macro substitutions on line while(match($0, /<[^>]*>/)) { macroName = substr($0, RSTART, RLENGTH) sub(macroName, macros[macroName]) } print } END { # Substitution for macro name at end of file if (macroName != "") print macros[macroName] # print "All macros:" # for (macroName in macros) { # print macroName ORS macros[macroName] # } } # # namevec "structure" # function namevec_Top() { return namevec_At(__nvlen - 1) } function namevec_TopDepth() { return __nvdepth[__nvlen - 1] } function namevec_At(_ind) { return "<" __nvnames[_ind] ">" } function namevec_Length() { return __nvlen } function namevec_Push() { match($0, /<[^>]*>/) name = substr($0, RSTART + 1, RLENGTH - 2) if (__nvlen > 0) { name = __nvnames[__nvlen-1] "/" name } __nvnames[__nvlen] = name __nvdepth[__nvlen++] = depth } function namevec_Pop() { delete __nvnames[--__nvlen] delete __nvdepth[__nvlen] }