Benutzer:Daniel Bohrer/Semantic M4rkup
Aus Stratum 0
____ _ _ __ __ _ / ___| ___ _ __ ___ __ _ _ __ | |_(_) ___ | \/ | __ _ _ __| | ___ _ _ __ \___ \ / _ \ '_ ` _ \ / _` | '_ \| __| |/ __| | |\/| |/ _` | '__| |/ / | | | '_ \ ___) | __/ | | | | | (_| | | | | |_| | (__ | | | | (_| | | | <| |_| | |_) | |____/ \___|_| |_| |_|\__,_|_| |_|\__|_|\___| |_| |_|\__,_|_| |_|\_\\__,_| .__/ |_| with the M4 macro processor
Inhaltsverzeichnis
M4
- Kernighan & Ritchie, 1977
- part of almost every Unix/Linux distribution
- Heavily used in GNU
autotools
- Simple mechanism:
- define macros
- when macro token is found in input, replace token with definition
- write input to output
Example 1: Hello World(?)
$ cat 01-helloworld.m4 define(HELLO, Ohai)dnl HELLO world.
$ m4 01-helloworld.m4 Ohai world.
Notes:
dnl
: Discard to Next Line- "comments"
- prevents unwanted whitespace in output
Example 2
$ cat 02-more-hello.m4 define(Nice, Happy)dnl define(HELLO, Nice to meet you)dnl HELLO World.
$ m4 02-more-hello.m4 Happy to meet you World.
What happened?
Example 2: step by step
Input | Macro definitions |
---|---|
> define(Nice, Happy)dnl define(HELLO, Nice to meet you)dnl HELLO World. |
Input | Macro definitions |
---|---|
> define(HELLO, Nice to meet you)dnl HELLO World. |
|
Input | Macro definitions |
---|---|
> define(HELLO, Nice to meet you)dnl HELLO World. |
|
Input | Macro definitions |
---|---|
> define(HELLO, Happy to meet you)dnl HELLO World. |
|
Input | Macro definitions |
---|---|
> HELLO World. |
|
Input | Macro definitions |
---|---|
> HELLO World. |
|
Input | Macro definitions |
---|---|
> Happy to meet you World. |
|
Expansion Rules (1)
- Macro expansion is recursive
- macros inside of macros are evaluated first (unless quoted)
define
is a macro itself
But maybe we don't want that.
Quoting
Quoting prevents unwanted macro replacement
$ cat 03-quoting.m4 define(`Nice', `Happy')dnl define(`HELLO', ``Nice' to meet you')dnl HELLO World. $ m4 02-quoting.m4 Nice to meet you World.
Parametric Macros
$ cat 04-params.m4 define(`HEADING', `<h1 id="$1">$2</h1>')dnl define(`PARA', `<p id="$1">$2</p>')dnl define(`ITALIC', `<i>$1</i>')dnl dnl HEADING(title, `This is the title') PARA(first_para, This is rendered as text. Parameters can even span multiple lines. If you include commas`,' be sure to include quotes.) PARA(second_para, This is normal text. ITALIC(This is italic.))
$ m4 04-params.m4 <h1 id="title">This is the title</h1> <p id="first_para">This is rendered as text. Parameters can even span multiple lines. If you include commas, be sure to include quotes.</p> <p id="second_para">This is normal text. <i>This is italic.</i></p>
Expansion Rules (2)
- Quoted text is simply stripped of the quotes
- Macro expansion is recursive
- macros inside of macros are evaluated first (unless quoted)
- inner macros can generate more parameters for outer macros
- macros inside of macros are evaluated first (unless quoted)
- Leading whitespace of parameters is removed
- The expansion of a macro is always re-evaluated
- read: "strip one layer of quoting, or expand again"
Rule of thumb:
- One quoting level per parentheses.
You probably noticed
M4 macros are a great way to build semantic markup.
- Semantics:
- Wikipedia: “the linguistic, and also philosophical study of meaning”
- more than only formatting
- ideally machine-readable
For example
- Write your meeting minutes in Markdown, using a “public macro interface” for e.g.:
- votes
- resolutions
- TODOs
- Write an M4 library for each output
- define the “public macro interface” accordingly
- Use the markup with multiple M4 “libraries” to convert your minutes to:
- human-readable formats like Markdown
- with consistent formatting
- via pandoc: HTML, ReST, LaTeX, PDF, …
- machine-readable formats like JSON, CSV, XML, …
- human-readable formats like Markdown
See: https://github.com/rohieb/minutes-m4rkup
example.m4rkdown
MEETING_MINUTES(Board meeting, 2016-09-01, 20:00, [Adam Ant, Henrietta Horse, Beatrice Bull], [Ephraim Elephant], [Adam Ant]) We talked about things for a while. * RESOLUTION(Resolution 2016-00, VOTE_ADOPTED(3,0,0), World Domination) * TODO(T2016-03, Adam Ant, Build Doomsday Machine) * Recent TODOs: * TODO(T2016-02, , Try out LAZZZORs from Evil Corp., [ * They make nice, cheap LAZZZORS * LAZZZORS are needed for Doomsday Machine]) * DONE(T2016-01, Beatrice Bull, Buy some space rockets) END(21:00)
example.markdown
Board meeting 2016-09-01 ======================== * Starting time: 20:00 * Attending: Adam Ant, Henrietta Horse, Beatrice Bull * Absent: Ephraim Elephant * Minute taker: Adam Ant We talked about things for a while. * __Resolution 2016-00 ✔ (3|0|0):__ World Domination * __TODO Adam Ant:__ Build Doomsday Machine * Recent TODOs: * __TODO:__ Try out LAZZZORs from Evil Corp.. * They make nice, cheap LAZZZORS * LAZZZORS are needed for Doomsday Machine * ~~__DONE Beatrice Bull:__ Buy some space rockets~~ * Ending at 21:00
example.json
{ "metadata": { "type": "Board meeting","date": "2016-09-01", "start_time": "20:00", "attendants": "Adam Ant, Henrietta Horse, Beatrice Bull", "absentees": "Ephraim Elephant", "keeper_of_minutes": "Adam Ant" }, "content": [ { "type": "resolution", "public": true, "ref": "Resolution 2016-00", "vote": { "approved": true, "pro": 3, "contra": 0, "abstain": 0 }, "text": "World Domination", "allocated_money": "", "notes": "" }, { "type": "todo", "public": true, "done": false, "ref": "T2016-03", "assigned": "Adam Ant", "text": "Build Doomsday Machine", "notes": "" }, { "type": "todo", "public": true, "done": false, "ref": "T2016-02", "assigned": "", "text": "Try out LAZZZORs from Evil Corp.", "notes":" * They make nice, cheap LAZZZORS * LAZZZORS are needed for Doomsday Machine" }, { "type": "todo", "public": true, "done": true, "ref": "T2016-01", "assigned": "Beatrice Bull", "text": "Buy some space rockets", "notes": "" } ], "end_time": "21:00" }