Posso usar um Lexer/analiser criado pela ANTLR para analisar o arquivo pddl e retornar dados a um programa Java?

StackOverflow https://stackoverflow.com/questions/3818442

  •  26-09-2019
  •  | 
  •  

Pergunta

Eu sou novo no ANTLR, mas já usei Flex/Bison antes. Quero saber se o que eu quero fazer usando o ANTLR é possível.

Quero analisar um arquivo PDDL usando o ANTLR e criar minha própria representação do conteúdo do arquivo PDDL em uma classe Java que escrevi como o arquivo PDDL é analisado (nas ações das regras?). Após a conclusão do arquivo, quero retornar a representação do objeto do conteúdo do arquivo ao programa Java para executar outras operações.

Então, essencialmente, quero invocar um analisador PDDL produzido pela Antler em um arquivo PDDL de dentro de um programa Java e retribuir um objeto que descreve o arquivo PDDL ao programa Java principal.

Isso é possível? Eu tentei olhar para a documentação, mas não encontrei uma boa resposta.

Muito obrigado.

Foi útil?

Solução

Então, essencialmente, quero invocar um analisador PDDL produzido pela Antler em um arquivo PDDL de dentro de um programa Java e retribuir um objeto que descreve o arquivo PDDL ao programa Java principal.

Isso é possível?

Claro.

Primeiro, você precisa descrever seu idioma em um arquivo gramática (Antlr). O mais fácil é fazer isso em uma gramática combinada. Uma gramática combinada criará um Lexer e um analisador para o seu idioma. Quando o idioma fica mais complexo, é melhor separar esses dois, mas, para começar, será mais fácil usar apenas um arquivo gramatical (combinado).

Digamos que o idioma PDDL seja apenas uma linguagem fácil: é uma sucessão de um ou mais números, seja na notação hexadecimal (0x12fd), octal (0745) ou decimal (12345) separada por espaços brancos. Este idioma pode ser descrito no seguinte arquivo gramática Antlr chamado PDDL.g:

grammar PDDL;

parse
  :  number+ EOF
  ;

number
  :  Hex
  |  Dec
  |  Oct
  ;

Hex
  :  '0' ('x' | 'X') ('0'..'9' | 'a'..'f' | 'A'..'F')+
  ;

Dec
  :  '0'
  |  '1'..'9' ('0'..'9')*
  ;

Oct
  :  '0' '0'..'7'+
  ;

Space
  :  (' ' | '\t' | '\r' | '\n'){$channel=HIDDEN;}
  ;

Nesta gramática, as regras (Parse, Número, Hex, ... são regras) que começam com um capital são Lexer-Rules. Os outros são rajadas de pastor.

A partir desta gramática, você pode criar um Lexer e um analisador como este:

java -cp antlr-3.2.jar org.antlr.Tool PDDL.g

que produz (pelo menos) os arquivos PDDLParser.java e PDDLLexer.java.

Agora crie uma pequena aula de teste na qual você pode usar essas classes Lexer e analisador:

import org.antlr.runtime.*;
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        File source = new File("source.txt");
        ANTLRInputStream in = new ANTLRInputStream(new FileInputStream(source));
        PDDLLexer lexer = new PDDLLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        PDDLParser parser = new PDDLParser(tokens);
        parser.parse();
    }
}

onde o conteúdo do source.txt o arquivo pode ser assim:

0xcAfE 0234
66678 0X12 0777

Agora compilar tudo .java arquivos:

javac -cp antlr-3.2.jar *.java

e execute a classe principal:

// Windows
java -cp .;antlr-3.2.jar Main

// *nix/MacOS
java -cp .:antlr-3.2.jar Main

Se tudo correr bem, nada está sendo impresso no console.

Agora você diz que deseja deixar o analisador retornar certos objetos com base no conteúdo do seu arquivo de origem. Digamos que queremos que nossa gramática retorne um List<Integer>. Isso pode ser feito incorporando "ações" em suas regras gramaticais como esta:

grammar PDDL;

parse returns [List<Integer> list]
@init{$list = new ArrayList<Integer>();}
  :  (number {$list.add($number.value);})+ EOF
  ;

number returns [Integer value]
  :  Hex {$value = Integer.parseInt($Hex.text.substring(2), 16);}
  |  Dec {$value = Integer.parseInt($Dec.text);}
  |  Oct {$value = Integer.parseInt($Oct.text, 8);}
  ;

Hex
  :  '0' ('x' | 'X') ('0'..'9' | 'a'..'f' | 'A'..'F')+
  ;

Dec
  :  '0'
  |  '1'..'9' ('0'..'9')*
  ;

Oct
  :  '0' '0'..'7'+
  ;

Space
  :  (' ' | '\t' | '\r' | '\n'){$channel=HIDDEN;}
  ;

Como você pode ver, você pode permitir que as regras retornem objetos (returns [Type t]) e pode incorporar o código java simples se o envolver { e }. o @init parte no parse A regra é colocada no início do parse Método no PDDLParser.java Arquivo.

Teste o novo analisador com esta classe:

import org.antlr.runtime.*;
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        File source = new File("source.txt");
        ANTLRInputStream in = new ANTLRInputStream(new FileInputStream(source));
        PDDLLexer lexer = new PDDLLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        PDDLParser parser = new PDDLParser(tokens);
        List<Integer> numbers = parser.parse();
        System.out.println("After parsing :: "+numbers);
    }
}

E você verá o seguinte sendo impresso no console:

After parsing :: [51966, 156, 66678, 18, 511]

Outras dicas

Isso certamente é possível, pois o ANTLR foi projetado para gerar analisadores que são invocados como parte de um sistema maior (por exemplo, um compilador ou um analisador de código estático).

Comece com Terence Parr's A referência definitiva de ANTLR: Construindo idiomas específicos de domínio. Ele é o autor da ANTLR, e também um professor incomumente claro e sem jargões sobre processamento de idiomas.

Martin Fowler's Idiomas específicos de domínio Usa a ANTLR em muitos de seus exemplos. Por exemplo, na página 200, ele mostra um exemplo simples de "Hello World", em que um programa Java chama a ANTLR para analisar um arquivo de pessoas para cumprimentar e, ao fazê -lo, emite as saudações. Aqui é onde o trabalho é realizado (página 206):

class GreetingsLoader. ..
  public void run() {
    try {
      GreetingsLexer lexer = new GreetingsLexer(new ANTLRReaderStream(input));
      GreetingsParser parser = new GreetingsParser(new CommonTokenStream(lexer));
      parser.helper = this;
      parser.script() ;
      if (hasErrors() ) throw new RuntimeException("it all went pear-shaped\n" +
 errorReport() ) ;
    } catch (IOException e) {
      throw new RuntimeException( e) ;
    } catch (RecognitionException e) {
      throw new RuntimeException( e) ;
    }
  }

Um terceiro bom livro é o novo de Terence no DSLS Padrões de implementação de idiomas. Ele descreve várias maneiras de usar o ANTLR, como por exemplo, para escrever um gerador de árvore de sintaxe abstrato para colocar em um compilador.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top