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'.