Skip to content

Commit

Permalink
完成while流程的解析,但还有一些可能导致内存泄露的问题没解决
Browse files Browse the repository at this point in the history
  • Loading branch information
thinszx committed Jan 17, 2021
1 parent e1ecace commit b4b426b
Show file tree
Hide file tree
Showing 17 changed files with 721 additions and 19 deletions.
17 changes: 13 additions & 4 deletions controlflow2.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ int if_check(char *cmd) {
syn_err((char*)"to many if levels(more than 10)"); // if嵌套语法错误
return SYN_ERR;
}
if (if_mode != NO_IF) {
if (if_mode != SAW_THEN && laststat != 0)
return DONT_EXEC;
if (if_mode != NO_IF) { // 当前if成功执行
set_ifenv(); // 开始进行嵌套if的执行
// return DONT_EXEC;
}
Expand All @@ -59,21 +61,21 @@ int if_check(char *cmd) {

// 检测then else fi
// TODO: 检测elif
if (strcmp(cmd, "then") == 0) { // then
if (strncmp(cmd, "then", 4) == 0) { // then
if (if_mode != SAW_IF)
syn_err((char*)"\'then\' unexpected");
else
if_mode = SAW_THEN;
return DONT_EXEC;
}
if (strcmp(cmd, "else") == 0) { // else
if (strncmp(cmd, "else", 4) == 0) { // else
if (if_mode != SAW_THEN)
syn_err((char*)"\'else\' unexpectd");
else
if_mode = SAW_ELSE;
return DONT_EXEC;
}
if (strcmp(cmd, "fi") == 0) { // fi
if (strncmp(cmd, "fi", 2) == 0) { // fi
if (if_mode != SAW_THEN && if_mode != SAW_ELSE)
syn_err((char*)"\'fi\' unexpected");
else
Expand Down Expand Up @@ -119,6 +121,13 @@ int save_env() {
return 0;
}

int check_inside(char* cmd) {
if (strncmp(cmd, "echo ", 5) == 0)
return 1;
else
return 0;
}

// 恢复原有的if环境
// 实质上等同于出栈操作
int restore_env() {
Expand Down
101 changes: 101 additions & 0 deletions eval.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#define _CRT_SECURE_NO_WARNINGS
/* 功能摘要
* 尝试执行赋值语句,在读到一条命令并去除其中可能存在的if/while等关键词后,首先执行的就是本文件中内容
* 功能说明
* 返回值反映了该语句是否为变量的赋值语句,返回值为0,则是,为-1,则不是
* 功能逻辑
* 在进行赋值时,会维护一个hash表,将变量名称以及它们的值作为键值对放在hash表中
* 根据返回值
*/
#include <stdio.h>
#include <ctype.h>
#include "varlib.h"
#include <Windows.h>

// 将$abc这样形式的字符串转变为$abc的值
int eval(char* src, char* dest, int len) {
int pos; // dest指针
char ch; // 当前字符
char* varval; // 指向变量

pos = 0;
while (ch = *src++) {
if (pos == len) // 越界检查
return -1;
if (ch == '\0' || ch == EOF) {
break;
}
// 本来觉得需要,后来发现在splitline.c里面已经做过转义了,这里的$一定是变量开头的,\$一定是转义
if (ch == '\\')
if (*src == '$') // 将\进行转义
{
dest[pos++] = *src;
src++;
continue;
}

if (ch != '$') // 不为变量字符
{
dest[pos++] = ch; // 写入缓冲区
continue;
}

/* 是$的情况 */
varval = getvar(&src); // 尝试读取变量名
if (strlen(varval) + pos >= len) // 越界检查
return -1;

strcpy(dest + pos, varval); // 写入变量
pos += strlen(varval); // 移动指针
}
dest[pos] = '\0';
return pos;
}

char* getvar(char** srcp) {
/*
* 尝试读取变量的全称,在过程中检查合法性
* 变量名称合法,返回变量名称
* 否则返回$,并保持*srcp不动
*/
char varname[VARLEN + 1]; // 变量名称
int pos; // 写入缓冲区的指针位置
char* cp; // 用来生成变量的指针

cp = *srcp;
pos = 0;

while (is_an_idchar(*cp, pos)) // 当前字符合法
varname[pos++] = *cp++;
varname[pos] = '\0';
*srcp = cp;

if (pos > 0) { // 变量字符合法
// cp = EVget(varname);
cp = value_lookup(varname);
//if (cp == NULL) // 本身找不到时返回值就是""
// cp = (char*)"";
}
else
cp = (char*)"$"; /* else return the $ */
return cp;
}


int isaname(char* s) {
/*
* 判定当前字符串是否是合法变量名
*/
int pos = 0;
while (*s && is_an_idchar(*s, pos++))
s++;

return ((!*s) && (pos != 0));
}

int is_an_idchar(char ch, int pos) {
/*
* 判定当前字符是否可以位于合法变量名中
*/
return (isalpha(ch) || ch == '_' || (isdigit(ch) && pos > 0));
}
48 changes: 44 additions & 4 deletions exec2.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#define _CRT_SECURE_NO_WARNINGS
#include "pch.h"
#include "winshell2.h"
#include "varlib.h"
#include <stdio.h>
#include <Windows.h>

Expand Down Expand Up @@ -34,24 +36,62 @@ DWORD WaitForSingleObject(
// errno_t err = fopen_s(&fp, "C:\\Users\\12176\\Desktop\\操作系统课设\\winshell\\multiif.sh", "r");
// errno_t err = fopen_s(&fp, "C:\\Users\\12176\\Desktop\\操作系统课设\\winshell\\fail-if.sh", "r");
// errno_t err = fopen_s(&fp, "C:\\Users\\12176\\Desktop\\操作系统课设\\winshell\\lessfi.sh", "r");
errno_t err = fopen_s(&fp, "C:\\Users\\12176\\Desktop\\操作系统课设\\winshell\\plusfi.sh", "r");
// errno_t err = fopen_s(&fp, "C:\\Users\\12176\\Desktop\\操作系统课设\\winshell\\plusfi.sh", "r");
// errno_t err = fopen_s(&fp, "C:\\Users\\12176\\Desktop\\操作系统课设\\winshell\\var_assign.sh", "r");
errno_t err = fopen_s(&fp, "C:\\Users\\12176\\Desktop\\操作系统课设\\winshell\\loop.sh", "r");
if (fp == NULL || err != 0) {
printf_s("Failed to open file!");
return -1;
}

int i = 0;
while (TRUE) {
// char newstr[MAXCMDLEN];
char* buf = readline(fp);
if (buf == NULL) {
if_check(buf);
break;
}
// 尝试进行变量的赋值
// 防止echo a=$a这样的代码出现,如果等号前有空格,那么一定不是赋值语句
if ((strncmp(buf, "if ", 3) != 0) && (strncmp(buf, "else ", 5) != 0) &&
(strncmp(buf, "while ", 6) != 0) && (strncmp(buf, "elif ", 5) != 0) && (check_inside(buf) != 1)) {
int assigned = value_assign(buf);
if (assigned == 0)
continue;
}

//if (eval(buf, newstr, MAXCMDLEN) == -1)
//{
// fprintf(stderr, "line too long\n");
// return 1;
//}
//printf("%s", newstr);

if (*buf == '\0') // 空行的情况
continue;
char** args = splitline(buf);
if (if_check(buf) == OK_EXEC)
process(buf); // 执行语句
char newstr[MAXCMDLEN];
// while
if (strncmp(buf, "while ", 6) == 0) {
char** tmplist = splitline(buf);
strcpy(buf, buf + 6);
set_loop_condition(buf);
char** lines = read_loop_block(fp);
int ret = execute_loop(lines);
if (ret == 1)
continue;
}

if (eval(buf, newstr, MAXCMDLEN) == -1) {
fprintf(stderr, "line too long\n");
return 1;
}
// printf("%s", newstr);
char** args = splitline(newstr);
if (if_check(newstr) == OK_EXEC)
process(newstr); // 执行语句


/*
// 特殊字符检查
// 若当前读到了if,开始进入条件语句处理程序
Expand Down
9 changes: 9 additions & 0 deletions loop-if.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
a=2
if echo $a
then
while [$a -lt 8]
do
a=$a+1
echo a=$a
done
fi
Loading

0 comments on commit b4b426b

Please sign in to comment.