How to match one or two tokens in a repetition in a macro?


#1

Macro newbie here!

I’m writing a small vm and I would like to use a macro to generate assemly instructions for the vm in the tests, like this:

secd![
  PUSH 92;
  PUSH 62;
  ADD;
]

The grammar is (OPCODE ARG?;)*. Is it possible to write a simple macro for this grammar?

My first attempt was something like

( $(  $($tt::tt)*  );*) => { vec![ $(secd_inst!($($tt)*) ),* ] }

But this should not work, because you can’t match ; separated token tree sequences, right?

Forgot to mention that macro should expand to something like

vec![
    Instr::Push(92),
    Instr::Push(62),
    Inst::Add,
]

#2

Simplest way to parse that particular grammar is to use a tt muncher.

Simplest way to parse is to change the grammar to enclose each instruction in (…)s, […]s or {…}s and match on $( ($($tt:tt)*) )*.

I’d say more, but it’s 4:10 am here.


#3

Thanks! I’ve ended up modifying the grammar: https://github.com/matklad/miniml/blob/master/src/machine/mod.rs#L223-L250.

I wish there were S-expression literals in Rust :slight_smile: In a statically typed language the only feasible way to work with S-expressions mush be macros anyway =/