Avatar billede donnib Nybegynder
09. oktober 2003 - 15:22 Der er 6 kommentarer og
1 løsning

recursive Descent Parser

Hej alle,
Jeg skal lave mig en lille parser i C#. Jeg har følgende string som skal parses :

{test} + {} <= 10 px

Der kan være uendlige mange af {test} men sefølgeligt med et andet navn. De to tuborg som er efter hinanden er korrekte. De skal være uden noget som helst i. Strengen er en regl som forklarer at den string den står ved dvs {} (forkortelse) plus test strengen må ikke være større eller lige med 10 px.

Er der nogen der kan hjælpe mig med at lave sådan en parser. Der vil altid KUN være + mellem {test} og det er kun muligt med <= . Jeg har svært ved at gennemskue hvordan man laver en Recursive Descent Parser. Det er måske lidt overkill men jeg kunne godt tænke mig at lave det sådan da jeg skal bruge det til et projekt.

donnib
Avatar billede casjachan Nybegynder
09. oktober 2003 - 15:55 #1
Jeg ved ikke om du kender til coco/R. Det skulle efter sigende være til at generere compilere med. Jeg har ikke selv brugt det, og kan derfor ikke hjælpe med brugen. Du kan finde den på siden
http://www.ssw.uni-linz.ac.at/Research/Projects/Compiler.html
Ved hjælp af denne, skulle du kunne lave en parser i c#
Avatar billede donnib Nybegynder
10. oktober 2003 - 00:35 #2
jeg vil gerne lave parseren i hånden så denne mulighed synes jeg ikke er tilgængelig nu men jeg har da hørt om det.

donnib
Avatar billede arne_v Ekspert
11. oktober 2003 - 18:16 #3
Det er faktisk ikke en helt simpel opgave.

Medmindre du har erfaring med den slags, så vil jeg anbefale et andet
approach.

Hvis du vil igang så er her noget kode som evaluerer expressions:

using System;
using System.Collections;

public enum TokenType
{
    Name = 1,
    Value = 2,
    Plus = 3,
    Minus = 4
}

public class Token
{
    private TokenType type;
    private int value;
    private string name;
    public Token(char op)
    {
        if(op == '+')
        {
            type = TokenType.Plus;
        }
        else if(op == '-')
        {
            type = TokenType.Minus;
        }
        else
        {
            throw new Exception("Illegal operator");   
        }
    }
    public Token(string name)
    {
        type = TokenType.Name;
        this.name = name;
    }
    public Token(int value)
    {
        type = TokenType.Value;
        this.value = value;
    }
    public TokenType Type {
        get
        {
            return type;   
        }
    }
    public int Value {
        get
        {
            return value;   
        }
    }
    public string Name {
        get
        {
            return name;   
        }
    }
    public override string ToString()
    {
        switch(type)
        {
            case TokenType.Name:
                return "[type=name," + name + "]";
            case TokenType.Value:
                return "[type=value," + value + "]";
            case TokenType.Plus:
                return "[type=+]";
            case TokenType.Minus:
                return "[type=-]";
            default:
                throw new Exception("Illegal token type");
        }
    }
}


class Scanner
{
    private string expr;
    private int ix;
    private Token next;
    public Scanner(string expr)
    {
        this.expr = expr;   
        ix = 0;
        next = null;
    }
    public Token GetNextToken()
    {
        Token res;
        if(next == null)
        {
            res = ParseNextToken();
        } else {
            res = next;
            next = null;
        }
        return res;
    }
    public void PushBackToken(Token tok)
    {
        next = tok;
        return;
    }
    public Token ParseNextToken()
    {
        while((ix < expr.Length) && (expr[ix] == ' '))
        {
            ix++;
        }
        if(ix >= expr.Length)
        {
            return null;
        }
        if(expr[ix] == '+')
        {
            ix++;
            return new Token('+');
        }
        else if(expr[ix] == '-')
        {
            ix++;
            return new Token('-');
        }
        else if(Char.IsDigit(expr[ix]))
        {
            int start = ix;
            int end = start;
            while((end < expr.Length) && Char.IsDigit(expr[end]))
            {
                end++;
            }
            ix = end;
            return new Token(Int32.Parse(expr.Substring(start, end-start)));
        }
        else if(expr[ix] == '{')
        {
            int start = ix + 1;
            int end = start;
            while((end < expr.Length) && (expr[end] != '}'))
            {
                end++;
            }
            ix = end + 1;
            return new Token(expr.Substring(start, end-start));
        }
        else
        {
            throw new Exception("Invalid expression");
        }
    }
}

public class Parser
{
    private Scanner scan;
    public Parser(string expr)
    {
        scan = new Scanner(expr);
    }
    public int Evaluate(Hashtable vars)
    {
        return Expr(vars);
    }
    private int Expr(Hashtable vars)
    {
        return RestExpr(Term(vars), vars);
    }
    private int RestExpr(int e, Hashtable vars)
    {
        Token tok = scan.GetNextToken();
        if(tok == null)
        {
            scan.PushBackToken(tok);
            return e;
        }
        else if(tok.Type == TokenType.Plus)
        {
            return RestExpr(e + Term(vars), vars);
        }
        else if(tok.Type == TokenType.Minus)
        {
            return RestExpr(e - Term(vars), vars);
        }
        else
        {
            scan.PushBackToken(tok);
            return e;
        }
    }
    private int Term(Hashtable vars)
    {
        Token tok = scan.GetNextToken();
        if(tok.Type == TokenType.Value)
        {
            return tok.Value;
        }
        else if(tok.Type == TokenType.Name)
        {
            return (int)vars[tok.Name];
        }
        else
        {
            throw new Exception("Unexpected terminal found");
        }
    }
}

class MainClass
{
    public static void Main(string[] args)
    {
        Parser pars = new Parser("{a} + 2 - {b} - 1");
        Hashtable vars = new Hashtable();
        vars.Add("a", 7);
        vars.Add("b", 3);
        Console.WriteLine(pars.Evaluate(vars));
    }
}

Det kan du jo prøve at rette til så det passer til dit formål.
Avatar billede donnib Nybegynder
19. oktober 2003 - 13:54 #4
Jeg har nu lavet mig en Recursive Descent Parser med lidt hjælp fra noget dokumentation.

Mihai
Avatar billede arne_v Ekspert
19. oktober 2003 - 14:01 #5
Tør man spørge hvad der var galt med min recursive decent parser ?
Avatar billede donnib Nybegynder
19. oktober 2003 - 14:04 #6
undskyld jeg har åbenbart trykket forkert :(

Kan jeg oprette et spørgsmål hvor du kan få pointene ?

Mihai
Avatar billede arne_v Ekspert
19. oktober 2003 - 14:07 #7
Hvis du vil kan du lave et spørgsmål "Point til arne_v" med et link
til dette spørgsmål.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester