xv6源码分析 003

xv6源码分析 003

在开始今晚的内容之前我先纠正以下昨天的一个错误

807eac367d0ee59c093f4317e5db349
struct cmd {
    int type;
};

代表的是在sh.c开头就定义的宏常量,系统调用号是通过汇编代码来传入的。修改之后的内容如下:

在这里插入图片描述

好啦,我们继续昨晚的内容吧。

sh.cmain函数中,主要工作的是这三个函数

  • getcmd()
  • parsescmd()
  • runcmd()

我们昨天已经看了第一个getcmd(),而且我也大致的给出了第二个函数的实现的思路,现在就来正式的看看吧。

sh.cparsescmd()

在看看具体的实现之前我们先看看两个基本的函数peek()gettoken()

  • peek()

    函数strchr(const char *s, char c)的作用的是找到字符串中第一个匹配字符c的字符的位置,并将对应的指针返回

    其实通过whitespace我们也能够看出这个函数是用来将一整条命令前面的一个单词进行过滤指向第二个单词

    我们看看这几个参数的含义:

    ps:表示一个字符串的起始地址

    es:表示需要检索的字符串的结束地址

    toks:表示在切割后的字符串中,查找我们传递进去的目标字符集是否存在

    char whitespace[] = " \t\r\n\v";
    int
    peek(char **ps, char *es, char *toks)
    {
      char *s;
    
      s = *ps;
      while(s < es && strchr(whitespace, *s))
        s++;
      *ps = s;
      return *s && strchr(toks, *s);
    }
    
  • gettoken()

    有点复杂,有待考究,我们只需要知道这个函数是用来解析命令即可

    int
    gettoken(char **ps, char *es, char **q, char **eq)
    {
      char *s;
      int ret;
    
      s = *ps;
      while(s < es && strchr(whitespace, *s))
        s++;
      if(q)
        *q = s;
      ret = *s;
      switch(*s){
      case 0:
        break;
      case '|':
      case '(':
      case ')':
      case ';':
      case '&':
      case '<':
        s++;
        break;
      case '>':
        s++;
        if(*s == '>'){
          ret = '+';
          s++;
        }
        break;
      default:
        ret = 'a';
        while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
          s++;
        break;
      }
      if(eq)
        *eq = s;
    
      while(s < es && strchr(whitespace, *s))
        s++;
      *ps = s;
      return ret;
    }
    

parsecmd(char *s)

struct cmd*
parsecmd(char *s)
{
  char *es;
  struct cmd *cmd;

  es = s + strlen(s);
  cmd = parseline(&s, es);		// <----- 
  peek(&s, es, "");
  if(s != es){
    fprintf(2, "leftovers: %s\n", s);
    panic("syntax");
  }
  nulterminate(cmd);
  return cmd;
}

可以看到在parsecmd(char *s)首先调用到了函数parseline(char **, char*)来处理命令,我们步进去看看

struct cmd*
parseline(char **ps, char *es)
{
  struct cmd *cmd;

  cmd = parsepipe(ps, es);
  while(peek(ps, es, "&")){
    gettoken(ps, es, 0, 0);
    cmd = backcmd(cmd);			// <----- backcmd()
  }
  if(peek(ps, es, ";")){
    gettoken(ps, es, 0, 0);
    cmd = listcmd(cmd, parseline(ps, es));		// <----- listcmd()
  }
  return cmd;
}

parseline(char **, char *)中,函数在调用真正的命令处理函数之前,又调用了parsepipe(char **, char *)

struct cmd*
parsepipe(char **ps, char *es)
{
  struct cmd *cmd;

  cmd = parseexec(ps, es);					// <----- parseexec()
  if(peek(ps, es, "|")){
    gettoken(ps, es, 0, 0);
    cmd = pipecmd(cmd, parsepipe(ps, es));	// <------ pipecmd()
  }
  return cmd;
}

和上面一样在正式对命令进行处理之前,调用了parseexec(char **, char *)

struct cmd*
parseexec(char **ps, char *es)
{
  char *q, *eq;
  int tok, argc;
  struct execcmd *cmd;
  struct cmd *ret;

  if(peek(ps, es, "("))
    return parseblock(ps, es);		// <------ parseblock()
    							  // 内部调用的是parseredir()

  ret = execcmd();
  cmd = (struct execcmd*)ret;

  argc = 0;
  ret = parseredirs(ret, ps, es);	// <----- parseredirs()
  while(!peek(ps, es, "|)&;")){
    if((tok=gettoken(ps, es, &q, &eq)) == 0)
      break;
    if(tok != 'a')
      panic("syntax");
    cmd->argv[argc] = q;
    cmd->eargv[argc] = eq;
    argc++;
    if(argc >= MAXARGS)
      panic("too many args");
    ret = parseredirs(ret, ps, es);		// <----- parseredirs()
  }
  cmd->argv[argc] = 0;
  cmd->eargv[argc] = 0;
  return ret;
}

parseblock(char **, char *)

struct cmd*
parseblock(char **ps, char *es)
{
  struct cmd *cmd;

  if(!peek(ps, es, "("))
    panic("parseblock");
  gettoken(ps, es, 0, 0);
  cmd = parseline(ps, es);
  if(!peek(ps, es, ")"))
    panic("syntax - missing )");
  gettoken(ps, es, 0, 0);
  cmd = parseredirs(cmd, ps, es);
  return cmd;
}

在这里插入图片描述

今天是2024/4/9,发现我也看不懂了,不死磕了大佬们,简单做了个实验,发现我还是太年轻了,

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
大致就是这个情况,好像并不会调用其他的函数,可能是我的测试命令太简单了,但是大致的调用流程和我上面给出的流程图是一样的,这种设计思路我们可以学习学习,其实我们也能够用函数指针的方法来实现,可能是由于我们命令有时候会比较复杂,比如当我们调用xarg或者grep这种复合命令的时候,就需要这种过滤的思维,来逐个解析命令。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/527432.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大屏可视化展示平台解决方案(word原件获取)

1.系统概述 1.1.需求分析 1.2.重难点分析 1.3.重难点解决措施 2.系统架构设计 2.1.系统架构图 2.2.关键技术 2.3.接口及要求 3.系统功能设计 3.1.功能清单列表 3.2.数据源管理 3.3.数据集管理 3.4.视图管理 3.5.仪表盘管理 3.6.移动端设计 3.1.系统权限设计 3.2.数据查询过程设…

如何使用vscode启动Flask并实现无公网IP远程访问内网服务

文章目录 1. 安装部署Flask2. 安装Cpolar内网穿透3. 配置Flask的web界面公网访问地址4. 公网远程访问Flask的web界面 本篇文章主要讲解如何在本地安装Flask&#xff0c;以及如何将其web界面发布到公网进行远程访问。 Flask是目前十分流行的web框架&#xff0c;采用Python编程语…

linux网络服务学习(5):iscsi

1.什么是iscsi 1.1 scsi SCSI是一种I/O技术&#xff0c;规范了一种并行的I/O总线和相关协议&#xff08;scsi协议&#xff09;。 SCSI总线通过SCSI控制器&#xff08;target&#xff09;来和硬盘之类的设备&#xff08;scsi设备&#xff09;进行通信&#xff0c;访问的客户端…

图形学物体拾取:CPU VS GPU

一、CPU – raycaster 射线包围盒是一种常用的方法&#xff0c;在 CPU 中进行拾取&#xff0c;性能较好&#xff0c;但是精度较差。当拾取频率不高时&#xff0c;可以考虑使用像素级精度的帧缓冲拾取Framebuffer Picker.射线投射涉及将射线投射到场景中并检查对象和射线之间的…

K8s技术全景:架构、应用与优化

一、介绍 Kubernetes的历史和演进 Kubernetes&#xff08;简称K8s&#xff09;是一个开源的容器编排系统&#xff0c;用于自动化应用程序的部署、扩展和管理。它最初是由Google内部的Borg系统启发并设计的&#xff0c;于2014年作为开源项目首次亮相。 初始阶段 Kubernetes的诞生…

网站想使用https安全协议,必须要安装ssl证书吗?

ssl证书作为保护网站数据传输安全的重要工具&#xff0c;被广泛应用于网站的安全加密通信中。很多人在初次接触ssl证书时&#xff0c;有一个常见的疑问&#xff1a;网站使用https协议必须要ssl证书吗&#xff1f; 答案是肯定的。   HTTPS是一种通过计算机网络进行安全通信的…

计算机网络 网络命令的使用

一、实验内容 1.PING网络命令的实验 ping 127.0.0.1(内部回环测试)ping 本主机的IP地址ping 默认网关地址ping远端目的地的IP地址ping localhostping域名 2.其他网络命令实验 命令用途ipconfig/all 显示当前系统网络配置&#xff0c;包括IP地址、子网掩码、默认网关等trace…

Unity MySql安装部署与Unity连接

1.前言 最近项目用到MySql&#xff0c;记录一下安装部署过程。 数据量过大或者需要管理用户数据的时候用mysql的话数据结构比较清晰明了&#xff0c;便于管理。 2.安装MySql Unity版本&#xff1a;2019.4.16 MySql版本&#xff1a;8.2.0 下载地址&#xff1a;MySql 下载…

LLM - 大语言模型(LLM) 的 应用技术

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/137503579 大语言模型(LLM) 的应用技术范围非常广泛,即: LangChain:开发框架,专为大型语言模型设计,以提高开发人工智能应用的效率,允许开发者将语言模…

Day17_学点JavaEE_转发、重定向、Get、POST、乱码问题总结

1 转发 转发&#xff1a;一般查询了数据之后&#xff0c;转发到一个jsp页面进行展示 req.setAttribute("list", list); req.getRequestDispatcher("student_list.jsp").forward(req, resp);2 重定向 重定向&#xff1a;一般添加、删除、修改之后重定向到…

整理的微信小程序日历(单选/多选/筛选)

一、日历横向多选&#xff0c;支持单日、双日、三日、工作日等选择 效果图 wxml文件 <view class"calendar"><view class"section"><view class"title flex-box"><button bindtap"past">上一页</button&…

AWS入门实践-在EC2上部署Wordpress网站

在AWS EC2上部署WordPress涉及到几个步骤&#xff0c;包括启动EC2实例、配置数据库、安装WordPress等。以下是详细的步骤和相应的命令脚本 第一步: 启动 EC2 实例 登录 AWS 控制台,进入 EC2 服务启动一个新的 EC2 实例,选择 Amazon Linux 2 AMI选择合适的实例类型(例如 t2.mi…

⼿机客户端画K线图流程

优质博文&#xff1a;IT-BLOG-CN 一、什么是K线流程 K线图是一种用于展示金融市场价格走势的图表。它通常由四个关键价格点组成&#xff0c;即开盘价、收盘价、最高价和最低价。K线图的流程可以简单概括为以下几个步骤&#xff1a; 【1】收集数据&#xff1a; 首先&#xff0c…

GPT-4对多模态大模型在多模态预训练、 理解生成上的启发

传统人工智能 模型往往依赖大量有标签数据的监督训练,而且一个模型一般只能解决一个任务,仅适用于单一场景, 这使得人工智能的研发和应用成本高,场景适应能力弱,难以规模化应用。 常见的多模态任务大致可以分为两类: 多模态理解任务,如视频 分类、视觉问答、跨模态检索、指代…

数据库——实验6 视图的创建与使用

1. 视图的定义 视图是根据需要以一个表或多个表为基础&#xff0c;选择满足一定条件的行或列数据的静态定义。它是一种逻辑对象&#xff0c;是一种虚拟表。视图并不生成行或列的永久副本&#xff0c;并不占用存储空 间&#xff0c;也就是说&#xff0c;视图就是保存在数据库中…

LLMs之FreeGPT35:FreeGPT35的简介、安装和使用方法、案例应用之详细攻略

LLMs之FreeGPT35&#xff1a;FreeGPT35的简介、安装和使用方法、案例应用之详细攻略 目录 FreeGPT35的简介 FreeGPT35的安装和使用方法 1、部署和启动服务 Node 2、使用 Docker 部署服务&#xff1a; 运行 Docker 容器以部署服务 使用 Docker Compose 进行更方便的容器化…

TCP/IP协议、HTTP协议和FTP协议等网络协议简介

文章目录 一、常见的网络协议二、TCP/IP协议1、TCP/IP协议模型被划分为四个层次2、TCP/IP五层模型3、TCP/IP七层模型 三、FTP网络协议四、Http网络协议1、Http网络协议简介2、Http网络协议的内容3、HTTP请求协议包组成4、HTTP响应协议包组成 一、常见的网络协议 常见的网络协议…

Docker之数据卷和Dockerfile

目录 一、Docker数据管理 二、数据卷 创建数据卷 查看数据卷 删除数据卷 挂载数据卷 三、数据卷容器 创建数据卷容器 测试数据卷容器 备份数据卷容器 还原数据卷容器 四、Dockerfile 什么是Dockerfile 基本结构 常用指令 快速入门 编写Dockerfile文件 构建镜…

Java-Tomcat

一、web补充技术 ①&#xff1a;B/S架构 主流的方式&#xff0c;只要有浏览器即可。编程方式直接基于socket即可 ②&#xff1a;javascript 简称js&#xff0c;早期只是实现在客户端的浏览器的动态效果&#xff0c;但服务端不会解释运行&#xff0c;所以本质上是静态资源。 …

使用新版FLIR (FLIR_ADAS_v2) 数据集创建yolo格式数据集(目标检测)

FLIR在2022.1.19发布了新版的FLIR_ADAS_v2&#xff0c;有着更多的类别和数量更丰富的图像。数据集同步注释热图像和无注释RGB图像供参考。本文章主要介绍如何使用FLIR_ADAS_v2中的rgb图像和thermal图像来制作yolo格式数据集。 1.官方数据集下载&#xff1a;FLIR_ADAS_v2数据集…