Разбор условного с лимоном

Я хочу разобрать следующий скрипт

str="HELLO"
if [ $str = "HELLO" ]; then
  echo FOO
fi

Первая строка str="HELLO" Я могу разобрать, и переменная будет сохранена для использования. Возможно запустить скрипт

str="HELLO"
echo $str

и получить вывод HELLO,

Но я пока не могу сделать условное утверждение if. Поэтому мне интересно, как мне поступить с условным утверждением. Я попытался определить эту грамматику лимона

expr(A) ::= IF '[' expr(B) EQEQ expr(C) '];then' expr(C) 'fi'.

Но это дает мне ошибку, что цитата является незаконным символом. Поэтому я не знаю, как написать грамматику для оператора if. Вся моя грамматика

%include
{
#include "types.h"
#include "openshell.h"
#include "assert.h"
}
%syntax_error { fprintf(stderr, "Syntax error\n"); }
%token_type { struct SToken* }
%type expr { int }

%nonassoc EQEQ NOTEQ SET LARGER SMALLER.
%left FOR WHILE IF.
%left PLUS MINUS.
%left TIMES DIVIDE.

program ::= expr(A). { setresult(A); /*printf("%d\n", A);*/ }
expr(A) ::= expr(B) PLUS expr(C). {A = B + C; }
expr(A) ::= expr(B) MINUS expr(C). {A = B - C; }
expr(A) ::= expr(B) TIMES expr(C). {A = B * C; }
expr(A) ::= expr(B) EQEQ expr(C). {if(B==C) {A=1;} else A=0;}
expr(A) ::= expr(B) NOTEQ expr(C). {if(B==C) {A=0;} else A=1;}
expr(A) ::= expr(B) LARGER expr(C). {if(B>C) {A=1;} else A=0;}
expr(A) ::= expr(B) SMALLER expr(C). {if(B<C) {A=1;} else A=0;}

expr(A) ::= expr(B) SET expr(C).  {A=C;B=C;}


expr(A) ::= IF '[' expr(B) EQEQ expr(C) '];then' expr(C) 'fi'.


expr(A) ::= FOR LPAR expr(B) SEMICOLON expr(C) SEMICOLON expr(D) RPAR expr(E). {A = D*B*E*C+1; } /* $((for ( 1 == 1 ; 2 == 2 ; 3 == 3 ) 55)) */
expr(A) ::= WHILE LPAR expr(B) RPAR expr(C).
{
while (B) { printf("%d", C);
}
A=C;printf("\n");
}
expr(A) ::= expr(B) DIVIDE expr(C).
{
    if (C != 0)
    {
        A = B / C;
    }
    else
    {
        fprintf(stderr, "divide by 0");
    }
}
expr(A) ::= LPAR expr(B) RPAR. { A = B; }
expr(A) ::= INTEGER(B).
{
//printf("the result = %s\n", B->token);
    A = B->value;
    //printf("Passed argument: %s\n", B->token);
}

Мой основной цикл выглядит следующим образом.

int main(int argc, char *argv[]) {
    bool donotrun = false;
    struct sigaction new_action, old_action;
    hashtable_t *hashtable = ht_create(65536);
    /* Set up the structure to specify the new action. */
    new_action.sa_handler = termination_handler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;

    sigaction(SIGINT, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN)
        sigaction(SIGINT, &new_action, NULL);
    sigaction(SIGHUP, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN)
        sigaction(SIGHUP, &new_action, NULL);
    sigaction(SIGTERM, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN)
        sigaction(SIGTERM, &new_action, NULL);

    int value;
    void *pParser;
    char *c;
    // struct SToken v[argc];

    int index = 0;
    int i;
    char *cvalue = NULL;
    const char *commandFile;
    bool quietFlag;

    while (1) {
        index = 0;
        i = getopt_long(argc, argv, "pc:vh",
                        options, &index);
        if (i == -1)
            break;
        switch (i) {
            case 'p': {
                exit(EXIT_SUCCESS);
            }
            case 'v': {
                printf("sh OpenShell version 0.1(a)\n");
                printf("Version: %s\n", VERSION);
                exit(EXIT_SUCCESS);

            }
            case 'h': {
                usage();
                exit(EXIT_SUCCESS);

            }
            case 'c': {
                cvalue = optarg;
                command(cvalue, hashtable);
                exit(EXIT_SUCCESS);
            }

            case 'f':
                /*
                 * Execute commands from file.
                 * This is used for osh script files.
                 * The quiet flag is also set.
                 */
                if ((argc != 1) || commandFile)
                    usage();

                quietFlag = true;
                argc--;

                break;


            case '?':
                if (optopt == 'c')
                    fprintf(stderr, "Option -%c requires an argument.\n", optopt);
                else if (isprint (optopt))
                    fprintf(stderr, "Unknown option `-%c'.\n", optopt);
                else
                    fprintf(stderr,
                            "Unknown option character `\\x%x'.\n",
                            optopt);
            default: {
                return 1;
            }
        }
    }
    getPath();
    pParser = (void *) ParseAlloc(malloc);
    char *copy;

    for (; ;) {
        bool scanning = true;
        bool calc = true;
        while (scanning) {
            char *line = NULL;
            line = readline("$ ");
            //return 0;
            if (line)
                copy = strdup(line);

            if (line && strstr(line, "=")) {
                donotrun = true;
                char str[128];
                char *ptr;
                strcpy(str, line);
                strtok_r (str, "=", &ptr);
                ht_set(hashtable, str, ptr);
            }

            if (!scanning)
                break;

            if (!isatty(fileno(stdin))) {
                *argv++;
                readFile(*argv++, hashtable);
                free(line);
                exit(0);
            }
            else {

                if (!donotrun) {
                    command(line, hashtable);
                }
                donotrun = false;
                add_history(copy);

            }
            free(copy);
        }
    }
    return 0;
}

Проблема в том, что я не знаю, как объявить квадратную скобку в грамматике для оператора if. Оператор if afaik является "составным" оператором условия и выражения, которое должно оцениваться, если условие истинно, поэтому будет задействовано как минимум 2 или 3 выражения. Я уже определил выражение равенства, которое работает:

expr(A) ::= expr(B) EQEQ expr(C). {if(B==C) {A=1;} else A=0;}

Но я получаю ошибку компилятора от lemon, когда пытаюсь заключить квадратные скобки в кавычки, и если я не использую кавычки, я получаю еще одну ошибку:

Illegal character on RHS of rule: "[".

Вышеуказанная ошибка, если я пытаюсь объявить:

expr(A) ::= IF [ expr(B) EQEQ expr(C) ];then expr(C) 'fi'.

1 ответ

Решение

Согласно документации:

Yacc и bison позволяют терминальным символам иметь либо буквенно-цифровые имена, либо отдельные символы, включенные в одинарные кавычки, например: ')' или '$'. Лимон не допускает эту альтернативную форму для терминальных символов. В Lemon все символы, терминалы и нетерминалы должны иметь буквенно-цифровые имена.

Другие вопросы по тегам