Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save djedr/7d21eac05ce2bbbca29b29d532a1fbe4 to your computer and use it in GitHub Desktop.
Save djedr/7d21eac05ce2bbbca29b29d532a1fbe4 to your computer and use it in GitHub Desktop.
Rapid talk 2017-02-15 outline

General-purpose text preprocessing with the C preprocessor. Featuring JavaScript.

2017-02-15 Dariusz Jędrzejczak

http://djedr.github.io


Outline

  1. Intro
  2. Applications
  3. Advantages
  4. Disadvantages
  5. Technical details
  6. Related work

0. Intro

  • C
  • C++
  • Objective-C

Who ever used any of the above?


Common feature?


The same preprocessor!


The C preprocessor

aka cpp


What is it?

a separate program invoked by the compiler as the first part of translation

[0]


1. Applications

This talk's goal is to show potential applications of cpp outside of the context of C/C++/Objective-C compilation.

Perhaps not everyone is aware that cpp can be used in this manner.

Maybe you might find it useful.


Common uses of cpp

inclusion of header files, macro expansions, conditional compilation

[0]


All of these could work in any language

the language of preprocessor directives is only weakly related to the grammar of C

[0]


Real-world example:

Believe it or not, we used this technique in our production JS workflow at Y[ahoo]! Search ~2007. Worked well.

-- Ryan Grove[1][2][3]


What for?

  • macros
    • for sharing constants
      • (across all text files -- across languages, e.g. JS, Java, CSS)
    • for syntax extension
    • for inlining code (avoiding function-call cost)
  • conditional compilation of blocks of code
  • splitting code across files via #include

[2][4]


Macros and conditional compilation

// include.js
#if DEBUG_VERSION
function assert(condition, message) {
    ...
}
#define ASSERT(x, ...) assert(x, ## __VA_ARGS__)
#else
#define ASSERT(x, ...)
#endif

[2][4]


And then just #include and use

// foobar.js
#include "include.js"

function myFunction(arg) {
    ASSERT(YAHOO.lang.isString(argvar), "arg should be a string");
    ...
#if DEBUG_VERSION
    YAHOO.log("Log this in debug mode only");
#endif
    ...
}

[2]


That was 10 years ago and now we have way more advanced and modern JS workflows.


But.


It "worked well" then. And it would still work now. cpp didn't change.

And it's not going anywhere. Stability and reliability are advantages.


2. Advantages


Widely available

  • essential part of every *C* compiler
    • by default on UNIX machines (cpp or gcc -E)
    • on Windows machines using cygwin or via MSVC /P
    • so a lot programmers used it and know how

Simple

  • Just string-based macros
    • Easy to understand: basically copy-paste and find-replace (with parameters)
  • Less complicated and easier to reason about than AST-based macros (like in Scala or Lisps)

Predictable

  • When not abused
  • conditional compilation either includes code or not and its completely controllable
    • unlike automatic dead code elimination or tree shaking
  • macros can be #undefed or #ifdefed away to ensure they have absolutely no effect on production code[4]
  • code inlining with macros has no runtime cost and is guaranteed
    • unlike automatic inlining done by modern JS engines

3. Disadvantages


Limited

  • Less power than AST-based macros
    • No notion of structure of underlying language
  • Awkward syntax for multiline macros
  • Macros do little more than simple text substitution
    • E.g. can't execute code, which would dynamically generate the text to be substituted

Unpredictable

  • When abused
  • When used for complex things and/or without caution

Somewhat coupled with C semantics

  • It was designed specifically for this language

Has some gotchas

make sure you use the UNIX EOL character before preprocessing your files. Otherwise, you’ll have some issues with multi-line macros

[2]


No (or difficult) integration with IDEs


4. Technical details


How to invoke

Just configure your web server to pipe Javascript through GNU cpp:

/usr/bin/cpp -P -undef -Wundef -std=c99 -nostdinc -Wtrigraphs -fdollars-in-identifiers -C

before minifying and compressing it for transmission.

[4]


5. Related work

  • SweetJS, AST-based macros for JavaScript[6]
  • My project, codenamed jstpp: general-purpose JavaScript-based text preprocessor[7]
    • Perhaps for next week

Thank you!

Questions?


Links

[0] https://en.wikipedia.org/wiki/C_preprocessor

[1] https://twitter.com/yaypie/status/633062183585234944

[2] http://www.julienlecomte.net/blog/2007/09/16/

[3] https://rreverser.com/es6-modules-are-dead-long-live-c-preprocessor/

[4] http://www.nongnu.org/espresso/js-cpp.html

[6] http://sweetjs.org/

[7] https://github.com/djedr/jstpp

[8] https://linux.die.net/man/1/cpp

[9] https://gcc.gnu.org/onlinedocs/cpp/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment