Roger Costello
Roger Costello

Reputation: 3209

How to generate XML directly within the parser using Java System.out.println

The input file that I want to parse consists of one or more rows and each row consists of a greeting (Hello or Greeting) followed by a person's first name. Here is a sample input:

Hello Roger
Greeting Sally

I want to create a parser that outputs XML. For the sample input I want the parser to generate this XML:

<messages>
    <message>
        <greeting>Hello</greeting>
        <person>Roger</person>
    </message>
    <message>
        <greeting>Greeting</greeting>
        <person>Sally</person>
    </message>
</messages>

I want the XML generated directly within the parser file (MyParser.g4) using Java System.out.println

Here is my lexer:

lexer grammar MyLexer;

GREETING : ('Hello' | 'Greeting') ;
ID  : [a-zA-Z]+ ;
WS  : [ \t]+ -> skip ;
EOL : [\n] ;

Here is my parser:

parser grammar MyParser;

options { tokenVocab=MyLexer; }

document:  (message+ {System.out.println("<messages>" + $message.value + "</messages>");});

message returns [String value]: (GREETING ID {value = "<message><greeting>" + $GREETING.text + "</greeting><name>" + $ID.text + "</name></message>";}) ;

I ran ANTLR on the lexer and parser and then compiled the Java code that ANTLR generated. This resulted in the following error message.

MyParser.java:154: error: cannot find symbol
                        value = "<message><greeting>" + (((MessageContext)_localctx).GREETING!=null?((MessageContext)_localctx).GREETING.getText():null) + "</greeting><name>" + (((MessageContext)_localctx).ID!=null?((MessageContext)_localctx).ID.getText():null) + "</name></message>";
                        ^
  symbol:   variable value
  location: class MyParser

What am I doing wrong, please?

Upvotes: 2

Views: 155

Answers (1)

Bart Kiers
Bart Kiers

Reputation: 170178

You forgot the $ before value, it must be: $value = "<message><greeting>" + ….

And you also want to print every message, so not:

message+ {System.out.println( … );}

which will print just once, but like this instead:

(message {System.out.println( … );})+

This ought to do it:

parser grammar MyParser;

options { tokenVocab=MyLexer; }

document
 : {System.out.println("<messages>");}
   ( message EOL? {
     System.out.println("  " + $message.value);
   })+
   {System.out.println("</messages>");}
   EOF
 ;

message returns [String value]
 : GREETING ID {
     $value = "<message><greeting>" + $GREETING.text + "</greeting><name>" + $ID.text + "</name></message>";
   }
 ;

Can be tested like this:

String source = "Hello Roger\nGreeting Sally";
MyLexer lexer = new MyLexer(CharStreams.fromString(source));
MyParser parser = new MyParser(new CommonTokenStream(lexer));
parser.document();

Upvotes: 2

Related Questions