2016-05-26 3 views
0

Je veux analyser le script suivantconditionnelle avec Parsing citron

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

La première ligne str="HELLO" je peux analyser et la variable pour l'utilisation est enregistré. Il est possible d'exécuter le script

str="HELLO" 
echo $str 

et obtenir la sortie HELLO.

Mais je ne peux pas encore faire l'instruction conditionnelle if. Je me demande donc comment je devrais faire avec la déclaration conditionnelle. J'ai essayé de définir cette grammaire de citron

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

Mais il me donne une erreur que la citation est illégale car. Donc, je ne sais pas comment écrire la grammaire pour l'instruction if. Tout mon grammar est

%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); 
} 

Ma boucle main ressemble à ce qui suit.

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; 
} 

Le problème est que je ne sais pas comment déclarer le crochet dans la grammaire de l'instruction if. Une instruction if est afaik une déclaration "composée" de la condition et l'expression à évaluer si la condition est vraie, donc il y aura au moins 2 ou 3 expressions impliquées. Je l'ai déjà défini l'expression de l'égalité qui fonctionne:

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

Mais je reçois une erreur de compilation de citron lorsque je tente de faire les crochets entre guillemets, et si je ne me cite alors je reçois une autre erreur:

Illegal character on RHS of rule: "[".

L'erreur ci-dessus si je tente et déclare:

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

Répondre

1

Selon the documentation:

Yacc and bison allow terminal symbols to have either alphanumeric names or to be individual characters included in single quotes, like this: ')' or '$'. Lemon does not allow this alternative form for terminal symbols. With Lemon, all symbols, terminals and nonterminals, must have alphanumeric names.