1

Following this question, I have ANTLR installed via HomeBrew:

brew install antlr

and it is installed on:

/usr/local/Cellar/antlr/<version>/

and installed the Python runtime via

pip3 install antlr4-python3-runtime

From here, I ran the

export CLASSPATH=".:/usr/local/Cellar/antlr/<version>/antlr-<version>-complete.jar:$CLASSPATH"

but when I run the command

grun <grammarName> <inputFile>

I get the infamous error message:

Can't load <grammarName> as lexer or parser

I would appreciate it if you could help me know the problem and how to solve it.

P.S. It shouldn't matter, but you may see the code I am working on here.

Foad S. Farimani
  • 12,396
  • 15
  • 78
  • 193

1 Answers1

1

This error message is an indication that TestRig (that the grun alias uses), can’t find the Parser (or Lexer) class in your classpath. If you’ve placed your generated Parser in a package, you may need to take the package name into account, but the main thing is that the generated (and compiled) class is in your classpath.

Also.. TestRig takes the grammarName AND a startRule as parameters, and expects your input to come from stdin.

I cloned your repo to take a closer look at your issue.

The immediate issue for why grun is giving you this issue is that you specified your target language in the grammar file (looks like I need to retract that comment about it not being anything in your grammar). By specifying python as the target language in the grammar, you didn't generate the *.java classes that the TestRig class (used by the grun alias) needed to execute.

I removed the target language option from the grammar and was able to run the grun command against your sample input. To get it to parse correctly, I took the liberty of modifying several things in your grammar:

  • Removed the target language (It's generally better to specify the target language on the antlr command line so that the grammar remains language agnostic (it's also essential if you want to use the TestRig/grun utility to test things out, since you'll need the Java target)).
  • changed SectionName lexer rule to section parser rule (with labeled alternatives. Having lexer rules like 'Body ' Integer will give you a single token with both the body keyword and the integer, that you'd then have to pull apart later (it also forces there to be only a single space between 'Body' and the integer).
  • set the NewLine token to -> skip (This is a bit more presumptive on my part, but not skipping NewLine will require modifying more parse rule to specify where all NewLine is a valid token.)
  • removed the StatementEnd lexer rule since I skiped the NewLine tokens
  • reworked theInteger and Float stuff to be two different tokens so that I could use the Integer token in the section parser rule.
  • a couple more minor tweaks just to get this skeleton to handle your sample input.

The resulting grammar I used was:

grammar ElmerSolver;

// Parser Rules

// eostmt: ';' | CR;

statement: ';';

statement_list: statement*;

sections: section+ EOF;
// section: SectionName /* statement_list */ End;

// Lexer Rules

fragment DIGIT: [0-9];
Integer: DIGIT+;

Float:
    [+-]? (DIGIT+ ([.]DIGIT*)? | [.]DIGIT+) ([Ee][+-]? DIGIT+)?;

section:
    'Header' statement_list End                         # headerSection
    | 'Simulation' statement_list End                   # simulatorSection
    | 'Constants' statement_list End                    # constantsSection
    | 'Body ' Integer statement_list End                # bodySection
    | 'Material ' Integer statement_list End            # materialSection
    | 'Body Force ' Integer statement_list End          # bodyForceSection
    | 'Equation ' Integer statement_list End            # equationSection
    | 'Solver ' Integer statement_list End              # solverSection
    | 'Boundary Condition ' Integer statement_list End  # boundaryConditionSection
    | 'Initial Condition ' Integer statement_list End   # initialConditionSection
    | 'Component' Integer statement_list End            # componentSection;

End: 'End';

// statementEnd: ';' NewLine*;

NewLine: ('\r'? '\n' | '\n' | '\r') -> skip;

LineJoining:
    '\\' WhiteSpace? ('\r'? '\n' | '\r' | '\f') -> skip;

WhiteSpace: [ \t\r\n]+ -> skip;

LineComment: '#' ~( '\r' | '\n')* -> skip;

With those changes, I ran

➜ antlr4 ElmerSolver.g4
javac *.java                                         
grun ElmerSolver sections -tree  < examples/ex001.sif

and got the output:

(sections (section Simulation statement_list End) (section Equation  1 statement_list End) <EOF>)
Mike Cargal
  • 6,610
  • 3
  • 21
  • 27
  • I have actually tried to put the generated files in the main folder too, getting the same error message as well. Maybe something is wrong with my [grammar file](https://github.com/AltElmer/ElmerSolverParser)? – Foad S. Farimani Apr 04 '21 at 20:38
  • 1
    If it ANTLR accepts it and generates source files (and they compile clean), then it’s almost certainly not an issue with your grammar. I’m sure that it’s a matter of the right command line and having your classes in the classpath. since you’ve posted a link to your source, I’ll clone it tomorrow and take a look to see if I can provide more precise guidance, but that error is TestRig saying “I can’t find the class to run what you’ve asked for” https://github.com/antlr/antlr4/blob/master/tool/src/org/antlr/v4/gui/TestRig.java (line 138) (catching ClassNotFoundException) – Mike Cargal Apr 04 '21 at 22:24
  • 2
    BTW, the Python runtime won’t have anything to do with using grun. That’s purely running Java stuff. – Mike Cargal Apr 04 '21 at 22:26