Pegjs: Fórum ou chat? Transmitindo valores para baixo / exibindo valores para cima?

Criado em 23 mar. 2017  ·  7Comentários  ·  Fonte: pegjs/pegjs

pegjs é simples e poderoso. Eu amo isso! Tenho algumas perguntas que não são abordadas na documentação:

Estou analisando isso, o que funciona, mas a regra parece estranha:

f = x => x * x

Se eu delegar para dizer Operador, não há como passar os valores para baixo. Se eu criar ValuesOperators e ou = e =>, é um pouco mais limpo, mas no nível superior ainda preciso verificar qual era. No exemplo de JavaScript, vejo o uso de {type: "Literal", value: ...}. Essa é a melhor maneira de repassar as informações?

  = values:Values body:(_ "=>" _ Expression)? assign:(_ "=" _ Expression)? {
      if (body && body.length > 0) {
        return new Function(values, body[3]);
      } else if (assign) {
        return new Assignment(values, assign[3]);
      } else {
        return values;
      }
    }

Obrigado!
Mike

Comentários muito úteis

Eu estava supondo que não voltar atrás e ser ganancioso significava que você tinha que trabalhar com "onde quer que você esteja", mas não é o caso. Yay!

Greedy significa apenas que, se encontrar uma correspondência, irá aceitá-la, correto? Mas se a regra inteira não corresponder, ela começará novamente do início na próxima partida. Isso torna muito mais fácil do que como eu estava tentando fazer.

x, y = 2 + 3.foo + "foo", 5 * 2

Isso é bastante fácil quando a atribuição pode ser correspondida separadamente de uma expressão regular, etc.

  = Assignment
  / Expression

Assignment
  = vars:Variables _ "=" _ expr:Expression

Variables
  = head:Identifier tail:(_ "," _ Identifier)*

...

Todos 7 comentários

Nas gramáticas, é essencial entender as regras. E você está fornecendo apenas sub .. isso não está claro para mim, como pode ficar claro para a máquina?
Gramáticas LALR são muito difíceis de escrever, mas mais fáceis do que LR e mais fáceis do que LL ..
A gramática PEG é fácil de escrever e mais difícil de escrever com eficiência.
Tem certeza de que está usando o brinquedo certo? Se você tem uma boa gramática PEG, você deve ser capaz de criar um transpiler ou interpretar tão facilmente quanto interpretar suas regras.

Você conhece boxing / unboxing em máquinas virtuais?

Como você pode ter values no lado esquerdo da atribuição? porque você tem este: body:(_ "=>" _ Expression)? terminado com ?

o que values significa em sua gramática? Você sabe o que é valor L ?

Você deve manter sua gramática semanticamente próxima. É difícil com PEG em alguns casos .. { type: "Literal", value: ... } é exatamente o que você precisa em AST. Veja em http://astexplorer.net/ como pode ser

Acabei de começar a usá-lo para experimentar, então sim, alguns dos nomes estão incorretos :) Eu escrevi alguns analisadores LL (1) simples, mas já faz um tempo. Só estou curioso para saber qual é a melhor maneira de lidar com as decisões. Vou simplificar para esta sintaxe:

a = b
ou
x => x * x

É mais apropriado fazer algo assim?

AssignmentOrFunction
= ident: Operador de identificador : IdentOperator {
if (operator.type === "Função") {
...
}

IdentOperator
= "="! ">" {return {type: "Atribuição"; }}
/ "=>" {...}

Para sua informação, "valores" era um termo que usei para designar uma lista de itens - seriam valores se usados ​​como uma tupla, mas variáveis ​​se usados ​​para definir os argumentos da função. Por exemplo (2 + 3).

Obrigado pelo seu tempo!

@mikeaustin É por sua conta :-)

Escrever gramáticas tem tudo a ver com reduções . A maioria é declaração . É como o sentense, você sabe, você tem gramáticas LL :-)

É sua responsabilidade definir a gramática no sentido (desculpe, tenho problemas com o inglês :-D às vezes)

Como você deseja processar AssignmentOrFunction? Isso é basicamente o mesmo que uma instrução em muitas linguagens, mas também pode ser um valor-R .
Por outro lado

    = "=" !">" { return { type: "Assignment"; } }
    / "=>" { ... }

pode ser melhor escrito como

    = "=>" { ... }
    / "=" { return { type: "Assignment"; } }

Pode estar errado .. mas parece que você quebrou sua frase em um fragmento não tão importante. Sem contexto, não é realmente importante o que você avalia isso.

PEGs são realmente difíceis de escrever porque você pode facilmente escrever regras inalcançáveis ​​ou você pode escrever regras que irão roubar sua frase e avaliá-las incorretamente, então se você é iniciante, você deve ter frases à esquerda e ASTs obrigatórios à direita o tempo todo, dez vezes mais testes automatizados do que regras gramaticais. Acredite em mim, você altera uma regra e todo o seu analisador falha.

E, claro, você deve brincar, escrever algo, de novo e de novo .. Não é trivial escrever calculadora de expressão efetiva com PEG, observe vários níveis de precedência .. PEG é melhor para análise geral.

Você não me dá mais contexto em sua pergunta, então é muito difícil adivinhar o que você realmente quer construir, mas eu acho que você deveria brincar mais com gramáticas, existe o AntLR , uma ótima ferramenta para aprender, GoldParser (LALR) (meu primeiro brinquedo :-)), alguns analisadores antigos que são bem testados, mais eficientes, mas divididos em tokenizer / analisador (lex e yacc mais antigos, flex e bison mais recentes), muitas portas deles.

PEG parece mais simples. É realmente. Mas sempre será mais perigoso ...

Muito obrigado! Oh, eu encontrei o grupo do Google para pegjs, mas não percebi porque estava na seção de desenvolvimento. Se eu tiver outras perguntas, com certeza irei lá.

Sim, a atribuição "x = y" é uma _ declaração_, mas "x => x * x" pode fazer parte de uma _expressão_, bem como "x == y", etc. "=" é um caso especial e assim é "=>" no sentido de que não são operadores regulares. Vou praticar mais e olhar mais de perto os exemplos. Eu gostaria que houvesse exemplos maiores do que a calculadora, mas menores do que os outros exemplos. Talvez se eu progredir, possa ser um exemplo :)

Para o meu projeto, gostaria de escrever uma linguagem simples para transpilar para JS. Os básicos são métodos externos com escopo léxico (sem patching de macaco, como Dylan ou CLOS, mas sem multimétodos), argumentos de palavra-chave, ADTs, talvez até mesmo tipagem estática opcional. "Simples" significa apenas que tudo funciona junto e há apenas uma maneira de fazer algo. Fazer algo simples pode ser _difícil_.

Além disso, existem bibliotecas como adt e multimétodos que podem se beneficiar da sintaxe nativa. Na verdade, isso poderia ser alcançado com o sweet , mas o sweet só pode estender o JS, não torná-lo mais simples. TypeScript tem opções como "--strictNullChecks" e suporta tipos de união inline, mas, novamente, ele estende JS de forma que deixa todas as coisas ruins ainda lá (coerções implícitas, "+" para concatinação de string, levantamento de escopo, etc.).

Mais uma vez, obrigado por toda a ajuda!
Mike

Eu estava supondo que não voltar atrás e ser ganancioso significava que você tinha que trabalhar com "onde quer que você esteja", mas não é o caso. Yay!

Greedy significa apenas que, se encontrar uma correspondência, irá aceitá-la, correto? Mas se a regra inteira não corresponder, ela começará novamente do início na próxima partida. Isso torna muito mais fácil do que como eu estava tentando fazer.

x, y = 2 + 3.foo + "foo", 5 * 2

Isso é bastante fácil quando a atribuição pode ser correspondida separadamente de uma expressão regular, etc.

  = Assignment
  / Expression

Assignment
  = vars:Variables _ "=" _ expr:Expression

Variables
  = head:Identifier tail:(_ "," _ Identifier)*

...

@mikeaustin PEGs têm escolha ordenada, o que significa que o primeiro padrão a corresponder em uma expressão irá corresponder automaticamente. O exemplo de @langpavel é uma boa maneira de expressar uma preferência por => relação a = . Você pode querer pensar mais sobre o que uma expressão pode ser em termos de "uma dessas coisas" em vez de "pegar todo este texto que poderia ser uma expressão e descobrir mais tarde"

  = FunctionExpression
  / Assignment
  / Value

Para demonstrar, criei um teste de gramática com o qual você pode brincar. É um pouco barulhento, mas tentei mantê-lo bem simples, ignorando algumas coisas como permitir espaços em branco e operadores extras. Observe o bloco Expression onde a mágica acontece. Além disso, usei coisas como SubExpression e ExpressionList como formas de lidar com "muitas dessas" situações; esse padrão funciona bem para mim, mantendo os separadores de lista e itens separados.

Em cada caso, estou tentando manter a gramática simples, tendo um item para cada tipo de correspondência. Há alguma redundância envolvida porque eu poderia reescrever de forma que tenhamos uma grande sequência de correspondência com todas as combinações possíveis, mas isso é difícil de seguir e raciocinar e deixa uma ambigüidade aberta que os PEGs podem eliminar com a escolha ordenada. Espero que ajude.

Vou dar uma olhada na gramática do teste, obrigado! Ajuda ver um subconjunto mínimo de uma linguagem, já que a gramática do JavaScript é muito grande.

@dmsnell Eu aprendi muito recentemente removendo regras e adicionando algumas novas à gramática JavaScript. Você pode ver as últimas aqui: impulso.pegjs . Eu removi a sintaxe de elisão [,,], alguns operadores, expressões de sequência, etc. e adicionei a sintaxe de tupla (1, 2) e a sintaxe de intervalo 1..5. Os números de vírgula flutuante requerem um decimal em ambos os lados para facilitar a análise dos intervalos literais.

Tenho trabalhado muito em tempo de execução ultimamente, mas quero voltar ao analisador para realmente emitir JavaScript. Estou entre empregos, então tenho um tempinho livre :) Algumas idéias para um dialeto limpo do JavaScript com métodos de extensão, parâmetros nomeados, características e mixins, sobrecarga de operador e tupla literal e sintaxe de intervalo.

Obrigado novamente!
Mike

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

audinue picture audinue  ·  13Comentários

futagoza picture futagoza  ·  13Comentários

futagoza picture futagoza  ·  6Comentários

richb-hanover picture richb-hanover  ·  7Comentários

StoneCypher picture StoneCypher  ·  8Comentários