Monday, May 9, 2016

C Preprocessor in PowerShell

I like to use C Preprocessor (often known as cpp) for preprocessing scripts such that I can easily alter the scripts without changing the body of the scripts. cpp provides #define, #ifdef, #else, #endif, and #undef among few others. And it's more powerful to support C programs.

For me, I just needed a simple way to use macros to alter the script. Hence, I wrote a very simple Preprocessor in PowerShell. It understands very rudimentary directives like #define, #ifdef, #else, #endif, #undef, and #ifndef. No nested #ifdef is supported at this time.

#
# cpp.ps1 -- C Preprocessor in PowerShell
#
# CJKim, 9-May-2016
#
# so far, it understands
#   #define
#   #undef
#   #ifdef
#   #ifndef
#   #else
#   #endif
#
# also, macros can be defined on the command line
#
param(
    [parameter(Mandatory=$True)]
    [string]$filePath,
    [string[]]$define
)

$dict = @{}
$inc = $True

if ($define.Count -gt 0) {
    foreach ($exp in $define) {
        ($k, $v) = $exp.Split('=')
        $dict.Add($k, $v)
    }
}

Get-Content -path $filePath | % {
    $line = $_.ToString()
    if ($line -match '^\s*#define\s+(\w+)\s*(.*)$') {
        $dict.Add($Matches[1], $Matches[2])
    }
    elseif ($line -match '^\s*#ifdef\s+(\w+)\s*$') {
        $inc = $dict.ContainsKey($Matches[1])
    }
    elseif ($line -match '^\s*#ifndef\s+(\w+)\s*$') {
        $inc = !$dict.ContainsKey($Matches[1])
    }
    elseif ($line -match '^\s*#else\s*$') {
        $inc = !$inc
    }
    elseif ($line -match '^\s*#endif\s*$') {
        $inc = $True;
    }
    elseif ($line -match '^\s*#undef\s+(\w+)\s*$') {
        $dict.Remove($Matches[1])
    }
    elseif ($inc) {
        $dict.Keys | % {
            $line = $line -replace $_, $dict[$_]
        }
        Write-Output $line
    }
}

1 comment: