用柠檬解析条件
Parsing a conditional with lemon
我要解析以下脚本
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 语句的语法。我的整个 grammar 是
%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);
}
我的 main 循环如下所示。
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 条件的 "compound" 语句和条件为真时要评估的表达式,因此至少会涉及 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'.
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.
我要解析以下脚本
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 语句的语法。我的整个 grammar 是
%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);
}
我的 main 循环如下所示。
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 条件的 "compound" 语句和条件为真时要评估的表达式,因此至少会涉及 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'.
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.