le parser de mon petit langage

a marqué ce sujet comme résolu.

bonjour, suite a la demande de @gasche sur le topic mon petit langage ( https://zestedesavoir.com/forums/sujet/16234/execution-de-mon-petit-langage/?page=3)

je creer ce topic pour parler de mon parser (que j’avais creer mais que je suis repartis a zero suite a un code mal forme :( )

je me permet de montrer mon code : https://github.com/antoineB24/tlang

@gasche : pour lalrpop merci

+1 -0

C’est intéressant par pure coïncidence je suis en train de prototyper un espèce de moteur JIT avec lalrpop, et c’est vraiment super bien pensé comme librairie. L’écriture de la grammaire c’est un régal, avec une détection des ambiguïtés/boucles etc qui est exactement dans le style des erreurs du compilo rust.

Le seul élément qui peut être rebutant imho c’est les "rusteries" c’est à dire bien penser à son modèle mémoire avec les références.

En définitive, je pense que ça vaut le coup pour toi d’y passer un peu plus de temps avec d’écrire un parseur de zéro :) (même si l’exercice est aussi intéressant en soi)

j’ai cette erreur :

error[E0432]: unresolved import `self::__lalrpop_util::lexer`
  --> calculator/target/debug/build/calculator-d540e26c11ded486/out/calculator1.rs:22:31
   |
22 |     use self::__lalrpop_util::lexer::Token;
   |                               ^^^^^ could not find `lexer` in `__lalrpop_util`
   

en suivant l’example de du book de lalrpop

+0 -0

C’est à toi de décider ce que tu veux faire pour ton projet, pourquoi demander de voter ?

Pour t’aider à choisir, je pense que tu devrais considérer ce qui t’intéresse le plus :

  • si c’est réfléchir au langage lui-même, utilise lalrpop, qui t’éviteras d’être distrait excessivement par le parsing ;
  • si c’est la programmation d’un parseur qui t’intéresse, alors fais-le à la main, mais alors tu pourrais tout aussi bien parser un langage connu pour t’éviter de réfléchir à la définition du langage lui-même.

bonjour , finalement j’ai choisit lalrpop, un petit probleme c’est le meme que j’avais avant (les block) ma gram

use std::str::FromStr;
use crate::tree::Expr;
use crate::lexer::Literal;

grammar;

pub Exprs = MultiLine<Expr>;
Block: Expr = "{" <e:Exprs> "}" => Expr::Block {body: e};
Num : Expr = <n:r"[0-9]+"> => Expr::Literal{value: Literal::Number(n.parse::<f64>().unwrap())} ;
Str : Expr = <s:r#"'(\\.|[^"])*'"#> => Expr::Literal{value: Literal::String(s[1..s.len()-1].to_string())} ;
Bool : Expr = <b:r#"true|false"#> => Expr::Literal{value: Literal::Bool(b == "true")} ;
IfExpr : Expr = "if" <e:Expr> "{" <e1:Expr>  "}" => Expr::IfThen{cond: Box::new(e), then: Box::new(e1)};
IfElseExpr : Expr = <e1:IfExpr> "else" <e2:Block>  => {
    match e1 {
        Expr::IfThen{cond, then} => Expr::IfThenElse{cond: cond, then: then, else_: Box::new(e2)},
        _ => panic!("Invalid if-else expression")
    }
};
Value = { Num, Str, Bool }
Expr = {
    Value,
    Block,
    IfExpr,
    IfElseExpr
}



MultiLine<T> : Vec<T> = {
    <mut v:(<T> ";") *> <e:T*>  => {
        v.into_iter().chain(e).collect()
    }
}

je ne sais pas comment implementer les block , ici lalrpop split bien les choses mais il dit qu’il connait pas le symbol ; donc en faite il ne le skip pas

merci pour votre atterntion

+0 -0

Hello,

Il faudrait faire un petit effort, la question est incompréhensible. Pourrais-tu poster un vrai message d’erreur et expliquer ton but ?

Je soupçonne qu’il y ait des ambiguïtés dans ta grammaire mais les messages d’erreur aideraient pour débugger.

bon, la 1er avec le message d’erreur , c’est regle :) donc pas besoin de l’explique,

par contre, la 2eme , c’est pas une erreur mais un probleme,

imaginons que dans mon langage il y a ceci:

if 1 {
  a 
  b 
} 

je veux enregistrer dans un vecteur chaque ligne d’un block (entre { et }) mais je ne sais pas comment faire , et donc je demande comment le faire en lalrpop ?

+0 -0

probleme resolut :) mais il y a un autre probleme :

mon code:

use std::str::FromStr;
use crate::tree::Expr;
use crate::lexer::Literal;

grammar;

pub Exprs = MultiLine<Expr>;
Block: Expr = "{" <e:Exprs> "}" => Expr::Block {body: e};
Num : Expr = <n:r"[0-9]+"> => Expr::Literal{value: Literal::Number(n.parse::<f64>().unwrap())} ;
Str : Expr = <s:r#"'(\\.|[^"])*'"#> => Expr::Literal{value: Literal::String(s[1..s.len()-1].to_string())} ;
// Bool : Expr = <b:r#"true|false"#> => Expr::Literal{value: Literal::Bool(b == "true")} ;
IfExpr : Expr = "if" <e:Expr> "{" <e1:Exprs>  "}" => Expr::IfThen{cond: Box::new(e), then: Box::new(Expr::Block {body: e1} )};
IfElseExpr : Expr = <e1:IfExpr> "else" <e2:Block>  => {
    match e1 {
        Expr::IfThen{cond, then} => Expr::IfThenElse{cond: cond, then: then, else_: Box::new(e2)},
        _ => panic!("Invalid if-else expression")
    }
};

ForExpr : Expr = "for" <e1:Expr> "in" <e2:Expr> "{" <e3:Exprs> "}" => Expr::For{
    name: Box::new(e1),
    iter: Box::new(e2),
    body: Box::new(Expr::Block {body: e3})
};

Ident : Expr = <i:r"[a-zA-Z_][a-zA-Z0-9_]*"> => Expr::Ident{name: i};

Value = { Num, Str, Ident };
Expr = {
    Value,
    Block,
    IfExpr,
    IfElseExpr,
    ForExpr,
    Ident
}



MultiLine<T> : Vec<T> = {
    <mut v:(<T> "\n") *> <e:T*>  => {
        v.into_iter().chain(e).collect()
    }
}

lalrpop confond ident et multiline : l’erreur :

  /Users/antoine/Documents/tlang/src/tlang.lalrpop:7:13: 7:27: Conflict detected

      when in this state:
    (<Expr> "\n")+ = (*) (<Expr> "\n")+ Expr "\n" ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    (<Expr> "\n")+ = (*) Expr "\n" ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Block = (*) "{" Exprs "}" ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Expr = (*) Block ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Expr = (*) ForExpr ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Expr = (*) Ident ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Expr = (*) IfElseExpr ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Expr = (*) IfExpr ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Expr = (*) Value ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Expr+ = (*) Expr ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Expr+ = (*) Expr+ Expr ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Exprs = (*) MultiLine<Expr> ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    ForExpr = (*) "for" Expr "in" Expr "{" Exprs "}" ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    ForExpr = "for" Expr "in" Expr "{" (*) Exprs "}" ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Ident = (*) r#"[a-zA-Z_][a-zA-Z0-9_]*"# ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    IfElseExpr = (*) IfExpr "else" Block ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    IfExpr = (*) "if" Expr "{" Exprs "}" ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    MultiLine<Expr> = (*) ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    MultiLine<Expr> = (*) (<Expr> "\n")+ ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    MultiLine<Expr> = (*) (<Expr> "\n")+ Expr+ ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    MultiLine<Expr> = (*) Expr+ ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Num = (*) r#"[0-9]+"# ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Str = (*) r#"'(\\\\.|[^\"])*'"# ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Value = (*) Ident ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Value = (*) Num ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]
    Value = (*) Str ["\n", "else", "for", "if", "in", "{", "}", r#"'(\\\\.|[^\"])*'"#, r#"[0-9]+"#, r#"[a-zA-Z_][a-zA-Z0-9_]*"#, EOF]

    and looking at a token `r#"[a-zA-Z_][a-zA-Z0-9_]*"#` we can reduce to a `MultiLine<Expr>` but we can also shift

merci pour votre attention

+0 -0

bonsoir, je reviens apres des longs changements : j’ai eu des problèmes au moment de l’écriture des op dans le parser : donc ca marche pour ceci :

4 + 5

mais pas pour ceci :

4 + 2 + 8 

c’est la meme chose pour tous les op que j’ai implemente (je vais vous montrez pas le code complet juste des extrais) :

Op: Expr = {
    <e1:Value> "+" <e2:Fact> => Expr::BinOp{left: Box::new(e1), op: Op::Add, right: Box::new(e2)},
    <e1:Value> "-" <e2:Fact> => Expr::BinOp{left: Box::new(e1), op: Op::Sub, right: Box::new(e2)},
    Fact
};


Fact: Expr = {
    <e1:Fact> "*" <e2:Value> => Expr::BinOp{left: Box::new(e1), op: Op::Mul, right: Box::new(e2)},
    <e1:Fact> "/" <e2:Value> => Expr::BinOp{left: Box::new(e1), op: Op::Div, right: Box::new(e2)},
    Value
};

// ... du code 

Value = { 
    Num, 
    Str, 
    Identifier, 
    True, 
    False, 
    Call, 
    Index, 
    List, 
    Range, 
    GetAttr,
    "(" <e:Expr> ")" => e,
};


Expr = {
    Block,
    IfExpr,
    IfElseExpr,
    ForExpr,
    WhileExpr,
    LetExpr,
    Op,
    Struct,
    CallStruct,
    CmpOp,
    FunDef,
    Impl,
    GetFunc,
    SetVar,
    IOp,
    Match
};

et donc je voudrais savoir pourquoi ceci ne marche pas et qu’elle est la solution : ``` 4 + 2 + 8

voila je vous remercie pour votre comprehension (la grammaire des op sont pris du manuel de lalrpop (j'avais testê mais non je n'y arrivais pas) ) j'espere que vous pouvez m'aidez , merci
+0 -0

Bonjour, alors il y a pas longtemps j’ai change de parser / lexer generateur j’ai pris donc pest qui supporte mieux la priorite des op et ne depand du reste du projecte , je n’ai donc plus besoin de la solution de ce probleme , je preferent pest parce que:

  • moins de bugs
  • message d’erreur plus facil a debug
  • priorite des op qui marchent tres bien (qui n’es pas possible dans lalrpop a moins de creer son propre lexer) mais il n’est moins complet que lalrpop (il check juste la syntax mais le ne genere pas d’AST)

Merci comme meme

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte