Tencent/matrix · error

unterminated %%ifdef starting on line

Error message

unterminated %%ifdef starting on line %d

What it means

Lemon's input preprocessor tracks %ifdef/%ifndef/%else/%endif conditionals while reading the grammar file. If the end of the file is reached while a conditional block is still open (exclude != 0), it prints 'unterminated %ifdef starting on line %d' naming the line where the block began, and exits 1.

Solutions

  1. Add the missing %endif at the end of the conditional block reported by the start line
  2. Search the .y file for all %ifdef/%ifndef and verify each has exactly one matching %endif (nesting order matters)
  3. Check for misspelled conditional keywords near the reported start line
  4. If the block came from a merge, re-diff against the original file to recover the dropped %endif

Example fix

// before (foo.y)
%ifdef FOO
rule ::= A.
// after
%ifdef FOO
rule ::= A.
%endif
Defensive patterns

Strategy: validation

Validate before calling

# python pre-check balancing conditional directives in order
import re,sys
stack=[]
for n,line in enumerate(open(sys.argv[1]),1):
    s=line.strip()
    if s.startswith(('%ifdef','%ifndef')): stack.append(n)
    elif s.startswith('%endif'): stack and stack.pop()
    elif s.startswith('%else') and not stack: sys.exit(f'stray %else at line {n}')
if stack: sys.exit(f'unterminated %ifdef starting on line {stack[0]}')

Prevention

When it happens

Trigger: A .y grammar file contains %ifdef or %ifndef without a matching %endif before EOF; a misspelled conditional keyword (e.g. `%endifs` or `%ednif`) that the scanner ignores; a nested conditional where one %endif was removed by an outer block's processing.

Common situations: Manual edits to grammar files that delete or comment out a %endif; merge conflicts resolved by dropping lines including %endif; copy-pasted conditional blocks where only part of the pair was copied; refactoring that moved rules across files leaving the opener behind.

Related errors


AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08). Data as JSON: /api/errors/a5fcd3e871638c92. Report an issue: GitHub.

Appendix: source

Thrown at matrix/matrix-android/matrix-sqlite-lint/src/lemon/lemon-gen/lemon.c:2423

        for(n=0; z[j+n] && !isspace(z[j+n]); n++){}
        exclude = 1;
        for(k=0; k<nDefine; k++){
          if( strncmp(azDefine[k],&z[j],n)==0 && strlen(azDefine[k])==n ){
            exclude = 0;
            break;
          }
        }
        if( z[i+3]=='n' ) exclude = !exclude;
        if( exclude ){
          start = i;
          start_lineno = lineno;
        }
      }
      for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
    }
  }
  if( exclude ){
    fprintf(stderr,"unterminated %%ifdef starting on line %d\n", start_lineno);
    exit(1);
  }
}

/* In spite of its name, this function is really a scanner.  It read
** in the entire input file (all at once) then tokenizes it.  Each
** token is passed to the function "parseonetoken" which builds all
** the appropriate data structures in the global state vector "gp".
*/
void Parse(gp)
struct lemon *gp;
{
  struct pstate ps;
  FILE *fp;
  char *filebuf;
  int filesize;
  int lineno;
  int c;

View on GitHub (pinned to 3b8293bd65)