Is it possible to define recursive/inter-dependent parse combinators in NimbleParsec?

Yes, you can have recursive combinators. But they need to be defined as defparsec in order to create their own context. They will need to be defined in their own module since they become functions. Something like (not complete):

defmodule Combinators do
  import NimbleParsec
  
  defparsec :asmexpr, 
    keyword_asm
    |> optional(keyword_volatile)
    |> concat(lparen)
    |> parsec(:expr)
    |> optional(asmoutput)
    |> concat(rparen)
    
  defparsec :primaryexpr,
    choice([
      parsec(:asmexpr),
      ifexpr,
      keyword_break |> optional(breaklabel) |> optional(parsec(:expr)),
      keyword_comptime |> parsec(:expr),
      keyword_nosuspend |> parsec(:expr),
      keyword_continue |> optional(breaklabel),
      keyword_resume |> parsec(Lexpr),
      keyword_return |> optional(parsec(:expr)),
      optional(blocklabel) |> concat(loopexpr),
      block,
      curlysuffixexpr
    ]) 

  # Other combinators
end