No Alternatives for Predicate Error

A somewhat broad question here but I can’t seem to find an answer anywhere in the documentation for TADS 3. The question is this:

Does anyone know what grammar production "predicate" has no alternatives defined means?

For example, let’s say you have just these examples from the library:

grammar commandPhrase(definiteConj) :
  predicate -> cmd_
  | predicate -> cmd_ commandOnlyConjunction -> conj_ *
  : CommandProduction
;

grammar commandOnlyConjunction(sentenceEnding):
  '.'
  | '!'
  | '?'
  : Production
;

grammar commandOnlyConjunction(nonSentenceEnding):
  'then'
  | 'and' 'then'
  | ',' 'then'
  | ',' 'and' 'then'
  | ';'
  : Production
;

And, with just those examples, it’s when compiling those that you get the above mentioned error.

I’m assuming it just means that the nonterminal predicate (used in the first of the three grammar statements of your example) isn’t defined anywhere. (Assuming the code contains no more grammar declarations than the three you have given.)

That does make sense. The challenge, however, is that even in the adv3lite or adv3 library, I don’t see where these predicates are defined. Those above grammar lines are defined in grammar.t but no specific predicate is defined. The full error is this:

The grammar production symbol "predicate" has no alternatives
defined.  This probably indicates that this symbol was accidentally
misspelled when used as a sub-production in a grammar rule.
Check for occurrences of this symbol in grammar rules, and 
correct the spelling if necessary.  If the symbol is spelled
correctly, add at least one grammar rule for this production.

The previously referenced grammar lines are currently all that I have in place. It’s not even clear to me where the cmd_ and conj_ are being referenced from. I see them mentioned in a comment in parser.t, on the CommandProduction, but that’s about it.

Context: this is all taking place for a class I’m teaching on how programming languages can be a little opaque in nature. I’m using a Playthology project to essentially build up an adv3/ad3lite like library, but from the ground up. So we’re building everything bit by bit, only including what we can see is needed immediately based on how one of the existing libraries works.

1 Like

Predicate productions are created by Action definitions. Specifically, each action creates a tagged predicate. So for example if you do a DefineTAction(Foo), you’ll end up with a predicate(Foo).

Edit: Correcting myself: Sorry, it’s the VerbRule macro that creates the tagged predicate for the Action, not DefineAction macro(s). Specifically the scrap of code that does it is in the language-specific header (in my case en_us.h):

#define VerbRule(tag)  grammar predicate(tag):

A rule that matches predicate->cmd_ will match all action predicates.

You can’t declare a grammar rule that only matches specific tagged productions, so you can’t write something like:

// YOU CAN'T DO THIS DO NOT COPY
grammar commandPhrase(FooOrBarOnly):
     predicate(Foo)->cmd_
     | predicate(Bar)->cmd_
     : CommandProduction
;

…so you don’t find tagged predicates anywhere in the grammar rules.

Ah! Indeed. That is it. Interestingly enough, I did come across that reference doing a global search for “predicate” but it wasn’t clear how this was all syncing up behind the scenes. Much thanks for getting me back on track.

1 Like

The other thing I’d mention (because this stuff isn’t particularly well documented and untangling it from source-diving is taxing) is to keep in mind (if you’re doing large-scare twiddling of the stock adv3 grammar) is that different bits of code use different productions as entry points in many places in the code.

I don’t know if that’s relevant to what you’re writing, but a while back I ended up chasing my tail over it for way too long, so it’s stuck in my head.

1 Like

Thank you for this. It’s good information.

Basically, the idea of the class is we take an existing project and then rewrite a new version of that from scratch, essentially starting the the program’s actual starting point and only writing what we know we need. The idea is to make the fewest possible assumptions about what’s needed and only go with the flow of the program. (We’ve done this with a variety of languages.)

We got up to the command loop with TADS (using the adv3lite library for our reference) which then calls the Parser. It’s here where we’re just hitting a bunch of problems because you can’t really tell what’s defined where. Sometimes things come from the library, sometimes they’re coming some part of the system library, and so on.

Right now my class is on the cusp of deciding TADS 3 is a little too opaque to continue with in this context. I personally still find it interesting but I get the frustration.

One more post (apologies for the spam!) I found this is what you can do to actually get past the error:

grammar predicate(Placeholder): () : Production;

That’s not mirrored by anything in the code of the library so I’m guessing that the inclusion of the VerbRules, which do define a grammar predicate, essentially allow the library to compile without the above placeholder.

Continuing to learn!

1 Like

Curious: what do you mean by TADS being too “opaque”?

Poor wording on my part. My DEVNOTES explain a little of that. But keep in mind the rationale: we’re building up a library from scratch, while using another library as a reference.

So the idea is seeing how easy it is to reason about the code in order to recreate it.

This would not apply to using such a library to create a game.

1 Like

Yeah. T3’s library internals, and in particular parser internals, really don’t appear to be documented in the expectation that anyone will be fiddling with them.

That said, what’s the scope of what you’re keeping and what you’re re-writing here, and what’s the minimal hello world you want to be capable of producing with the result?

Because this (on a linux command line, assuming the existence of FrobTADS on the system and in the user’s path) produces something “playable” (in the sense that it will run without error, exiting immediately) in a T3 interpreter:

echo "main(){}" > source.t && t3make -o game.t3 -source source.t

That is, if you don’t include anything from adv3/adv3lite, any of the language-specific headers, or anything like that “raw” TADS3 is perfectly happy with a “library” and “game” that, put together, comprise just an empty main().

1 Like

I confirm Jbg’s example (I appropriately changed the output filename…):

-rw-r--r-- 1 pigi pigi 27058  4 set 19.43 _main.t3o
-rw-r--r-- 1 pigi pigi  5508  4 set 19.43 _main.t3s
-rw-r--r-- 1 pigi pigi     9  4 set 19.43 source.t
-rw-r--r-- 1 pigi pigi  1496  4 set 19.43 source.t3o
-rw-r--r-- 1 pigi pigi   685  4 set 19.43 source.t3s
-rw-r--r-- 1 pigi pigi  7917  4 set 19.43 zero.t3

whose raise another, interesting, question: the relevant difference between the object files (t3o) and the binary (t3) seems to point toward some good optimisation of the latter, perhaps something akin to inform 6.4x’s OMIT_UNUSED_ROUTINES ?

Best regards from Italy,
dott. Piergiorgio.