Бизон приведение между типами выражений - PullRequest
0 голосов
/ 27 апреля 2018

У меня есть следующий код бизона, и следующие операторы работают нормально.

1 + 1
1.0 + 1.0

Но я хочу, чтобы следующее утверждение сработало

1.0 + 1

Я понимаю, что приведенный ниже код неоптимален, но меня попросили сохранить его в этом формате.

    %{
    #include <stdio.h>
    #include <math.h>
    #include <ctype.h>
    #include <string.h>
    #include <errno.h>

    /* Prototypes */
    int yylex(void);
    void yyerror(char *);

    int isFloat = 0;
    %}

    %union {
        int iVal;
        double fVal;
    }

    %token <iVal> INTEGER
    %token <fVal> FLOAT

    %type <iVal> expri termi utermi factori parti
    %type <fVal> exprf termf utermf factorf partf 

    %%
    command : expri         {printf("%d\n", $1); return;}
            | exprf     {printf("%f\n", $1); return;}
            ;

    expri   : expri '+' termi   {$$ = $1 + $3;}
            | expri '-' termi   {$$ = $1 - $3;}
            | utermi        {$$ = $1;}
            ;
    termi   : termi '*' factori     {$$ = $1 * $3;} 
            | termi '/' factori {$$ = $1 / $3;}
            | termi '%' factori     {$$ = $1 % $3;}
            | factori       {$$ = $1;}
            ;
    utermi  : utermi '*' factori    {$$ = $1 * $3;} 
            | utermi '/' factori    {$$ = $1 / $3;}
            | utermi '%' factori    {$$ = $1 % $3;}
            | '-' factori       {$$ = -$2;}
            | factori       {$$ = $1;}
            ;
    factori : factori '^' parti {$$ = pow($1, $3);}
            | parti         {$$ = $1;}
            ;
    parti   : '(' expri ')'     {$$ = $2;} 
            | INTEGER       {$$ = $1;}
            ;
    /* FLOAT RULES */
    exprf   : exprf '+' termf   {$$ = $1 + $3;}
            | exprf '-' termf   {$$ = $1 - $3;}
            | utermf        {$$ = $1;}
            ;
   termf    : termf '*' factorf     {$$ = $1 * $3;} 
            | termf '/' factorf {$$ = $1 / $3;}
            | termf '%' factorf     {$$ = fmodf($1, $3);}
            | factorf       {$$ = $1;}
            ;
    utermf  : utermf '*' factorf    {$$ = $1 * $3;}
            | utermf '/' factorf    {$$ = $1 / $3;}
            | utermf '%' factorf    {$$ = fmodf($1,$3);}
            | '-' factorf       {$$ = -$2;}
            | factorf       {$$ = $1;}
            ;
    factorf : factorf '^' partf {$$ = pow($1, $3);}
            | partf         {$$ = $1;}
            ;
    partf   : '(' exprf ')'     {$$ = $2;}
            | FLOAT         {$$ = $1;}
            ;
    %%

Хотя оба типа отлично работают в своих собственных ветвях, структура (очевидно) очень неоптимальна с сильным дублированием, но я не знаю обходной путь и не знаю, как распределять между ними.

1 Ответ

0 голосов
/ 28 мая 2018

Существует несколько других способов решения этой проблемы:

  1. Самым простым решением (если вам не нужна информация о типе) было бы привести целые числа в тип double, и тогда вы сможете объединить правила parti и partf, и т.д. в одну. Однако это действительно изменит структуру, так что это может быть не то, что вы хотите.

  2. Если вам нужна информация о типе, как предположил Пол Огилви, вам, вероятно, понадобится некоторая структура Val, которая содержит объединение целого / двойного с тегом типа. Опять же, это может быть не то, что вы хотите, потому что это требует немного больше усилий. Но ...

  3. Я подумал об этом немного больше, может быть, может быть найдется возможное решение, которое минимизирует изменения в вашем существующем языковом формате. По сути, мы добавляем «расширяющие» правила преобразования из целого числа в число с плавающей точкой:

    exprf: /* other exprf rules */
         | expri { $$ = $1; /* Implicit integer widening conversion*/}
    termf: /* other termf rules */
         | termi { $$ = $1; }
    utermf: /* other utermf rules */
          | utermi { $$ = $1; }
    /* ... */
    

    Это было бы довольно хакерским и громоздким решением из-за возникающих конфликтов уменьшения-уменьшения и сдвига-уменьшения. (Например, выражение 1 + 1 может быть уменьшено до expri или exprf). Возможно, вы захотите взглянуть на glr-parsing и слияния анализаторов glr , чтобы исправить некоторые неоднозначности. Я надеюсь, что это то, что вы ищете.

Первые два являются более элегантными решениями, но, возможно, если вам действительно нужно, третий вариант является жизнеспособным (я советую использовать bison -v, чтобы попытаться отладить эти конфликты, если вы выберете эту опцию, и попробуйте сыграть немного в зубрах).

...