欧美麻豆久久久久久中文_成年免费观看_男人天堂亚洲成人_中国一级片_动漫黄网站免费永久在线观看_国产精品自产av一区二区三区

中培偉業IT資訊頻道
您現在的位置:首頁 > IT資訊 > IT運維 > 如何構建一個Linux Shell(四)

如何構建一個Linux Shell(四)

2020-07-24 17:41:30 | 來源:中培企業IT培訓網

這是有關如何構建Linux Shell的教程的第四部分。在這一部分中,我們將向我們的外殼添加符號表。的符號表是用于由數據結構的編譯器和解釋器來存儲變量如表中的條目。每個條目都包含一個鍵(變量的名稱)和一個關聯的值(變量的值)。鍵通常是唯一的,也就是說,我們不能有兩個共享相同鍵的條目(即,不能有兩個共享相同變量名的變量)。

通常,Linux Shell在啟動時會填充其符號表。填充符號表后,編譯器或解釋器可以輕松地在表中搜索變量以檢索該變量的值。我們還可以執行類型檢查,執行作用域規則(例如,使變量僅對聲明其的函數可見),并將shell變量導出到外部命令。

為了填充符號表,外殼程序讀取環境變量列表,該環境變量列表從其父進程(通常是登錄用戶的進程或登錄進程的子進程)傳遞到外殼程序。Shell將每個變量(及其值)添加到符號表中。然后,我們可以使用適當的內置實用程序隨意編輯,刪除或導出shell變量(我們將在本系列的稍后部分中討論)。

  為什么我們需要符號表?

簡而言之,符號表使我們能夠定義外殼變量,修改它們的值,在執行變量擴展時使用不同外殼變量的值以及將變量導出到外部命令。在本系列后面的內容中,當我們討論位置和特殊外殼參數時,符號表也將變得很方便。

每當您要求外殼程序回顯,導出或未設置外殼程序變量的值時,您實際上就是在要求外殼程序訪問和/或修改其符號表。所有外殼程序都有某種符號表實現,盡管某些外殼程序可能具有不同的名稱。

例如,假設您調用了以下命令:

echo $PATH

哪個應該給你類似的輸出:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

您可能知道 echo 該命令與您在屏幕上看到的輸出無關,除了以下事實: echo打印出路徑。它的外殼究竟是誰明白$PATH 代表外殼變量名稱。

也是貝殼代替了單詞$PATH 帶有實際路徑值,然后將其傳遞給 echo。的echo 命令只是回顯了外殼程序傳遞的參數,這是您在屏幕上看到的可執行路徑。

因此,為了能夠定義,修改,取消設置和導出Shell變量,我們首先需要實現符號表。讓我們看看接下來如何做。

  實施符號表

有多種方法可以實現符號表,常見的方法是鏈表,哈希表和二進制搜索樹。每種方法都有優點和缺點,我們沒有時間或空間來詳細討論每種方法。為了我們的目的,我們將使用鏈表,鏈表是最容易實現的,并且在訪問速度和內存使用方面都相當不錯。

(注:如果你想使用的外殼任何東西比學習其他的,你應該考慮改變符號表執行到使用哈希表或二進制樹可以找到哈希表實現的例子這里)。

現在,讓我們來破解該代碼。在您的源目錄中,創建一個名為symtab (調用 mkdir symtab從您的終端仿真器)。導航到該目錄(cd symtab)并創建一個名為 symtab.h。將以下代碼添加到剛創建的頭文件中:

#ifndef SYMTAB_H

#define SYMTAB_H

#include "../node.h"

#define MAX_SYMTAB 256

/* the type of a symbol table entry's value */

enum symbol_type_e

{

SYM_STR ,

SYM_FUNC,

};

/* the symbol table entry structure */

struct symtab_entry_s

{

char *name;

enum symbol_type_e val_type;

char *val;

unsigned int flags;

struct symtab_entry_s *next;

struct node_s *func_body;

};

/* the symbol table structure */

struct symtab_s

{

int level;

struct symtab_entry_s *first, *last;

};

/* values for the flags field of struct symtab_entry_s */

#define FLAG_EXPORT (1 << 0) /* export entry to forked commands */

/* the symbol table stack structure */

struct symtab_stack_s

{

int symtab_count;

struct symtab_s *symtab_list[MAX_SYMTAB];

struct symtab_s *global_symtab, *local_symtab;

};

struct symtab_s *new_symtab(int level);

struct symtab_s *symtab_stack_push(void);

struct symtab_s *symtab_stack_pop(void);

int rem_from_symtab(struct symtab_entry_s *entry, struct symtab_s *symtab);

struct symtab_entry_s *add_to_symtab(char *symbol);

struct symtab_entry_s *do_lookup(char *str, struct symtab_s *symtable);

struct symtab_entry_s *get_symtab_entry(char *str);

struct symtab_s *get_local_symtab(void);

struct symtab_s *get_global_symtab(void);

struct symtab_stack_s *get_symtab_stack(void);

void init_symtab(void);

void dump_local_symtab(void);

void free_symtab(struct symtab_s *symtab);

void symtab_entry_setval(struct symtab_entry_s *entry, char *val);

#endif

的 symbol_type_e枚舉定義了我們的符號表條目的類型。我們將使用類型SYM_STR 表示外殼變量,以及 SYM_FUNC 表示函數(在本系列后面的部分中,我們將介紹shell函數)。

的 struct symtab_entry_s結構代表我們的符號表條目。該結構包含以下字段:

.name =>此條目表示的shell變量(或函數)的名稱。

.val_type => SYM_STR 對于外殼變量, SYM_FUNC 用于外殼函數。

.val =>字符串值(僅適用于Shell變量)。

.flags =>表示我們將分配給變量和函數的不同屬性,例如export和readonly標志(我們將在本系列的后面部分處理這些標志)。

.next =>指向下一個符號表條目的指針(因為我們將表實現為單鏈接列表)。

.func_body=>對于外殼函數,是函數主體的抽象語法樹或AST(我們在本教程的第一部分中討論了AST )。

的 struct symtab_s結構表示單個符號表。首先,我們將使用一個符號表,在其中定義所有的shell變量。稍后,當我們討論外殼函數并開始使用腳本文件時,我們將需要定義更多的符號表。

第零個符號表將是全局表,在其中我們將定義全局變量(shell可以訪問的全局變量,以及由它執行的所有函數和腳本)。

符號表中排名第一的符號表是本地表,我們將在其中定義我們的本地變量(這些變量只能由聲明了它們的shell函數或腳本訪問)。通過以這種方式級聯符號表,我們有效地實現了變量作用域。

我們的 struct symtab_s 結構包含以下字段:

.level =>對于全局符號表為0,對于局部符號表為1及更高。

.first, last =>分別指向表的鏈表中第一個和最后一個條目的指針。

現在,要能夠如上所述層疊符號表,我們需要定義并實現符號表棧。甲堆棧是一個后進先出,或LIFO,數據結構,其中的最后一個項目中加入(或推)是移除(或第一項彈出)。的struct symtab_stack_s結構代表我們的符號表堆棧。該結構包含以下字段:

.symtab_count =>當前堆棧中符號表的數量。

.symtab_list=>指向堆棧符號表的指針數組。第零項指向全局符號表,而symtab_count-1項目指向最后一個(或本地)符號表。堆棧最多可容納MAX_SYMTAB 項,我們在頭文件的開頭將其定義為256。

.global_symtab, local_symtab =>分別指向全局和局部符號表的指針(為了易于訪問)。

我們將在本課程的稍后部分實現堆棧。現在,我們將從編寫使用符號表所需的功能開始。

  符號表功能

創建 symtab.c 文件(在 symtab 子目錄),然后添加以下代碼開始:

#include

#include

#include

#include "../shell.h"

#include "../node.h"

#include "../parser.h"

#include "symtab.h"

struct symtab_stack_s symtab_stack;

int symtab_level;

void init_symtab(void)

{

symtab_stack.symtab_count = 1;

symtab_level = 0;

struct symtab_s *global_symtab = malloc(sizeof(struct symtab_s));

if(!global_symtab)

{

fprintf(stderr, "fatal error: no memory for global symbol table ");

exit(EXIT_FAILURE);

}

memset(global_symtab, 0, sizeof(struct symtab_s));

symtab_stack.global_symtab = global_symtab;

symtab_stack.local_symtab = global_symtab;

symtab_stack.symtab_list[0] = global_symtab;

global_symtab->level = 0;

}

首先,我們有兩個全局變量:

.symtab_stack =>指向符號表堆棧的指針(每個外殼僅需要一個堆棧)。

.symtab_level =>我們當前在堆棧中的級別(如果正在使用全局符號表,則為0,否則為非零)。

的 init_symtab() 函數初始化符號表堆棧,然后為全局符號表分配內存并進行初始化。

接下來,添加以下功能:

struct symtab_s *new_symtab(int level)

{

struct symtab_s *symtab = malloc(sizeof(struct symtab_s));

if(!symtab)

{

fprintf(stderr, "fatal error: no memory for new symbol table ");

exit(EXIT_FAILURE);

}

memset(symtab, 0, sizeof(struct symtab_s));

symtab->level = level;

return symtab;

}

我們稱 new_symtab() 每當我們想要創建一個新的符號表時(例如,當我們要執行一個shell函數時),函數就起作用。

接下來,添加以下功能:

void free_symtab(struct symtab_s *symtab)

{

if(symtab == NULL)

{

return;

}

struct symtab_entry_s *entry = symtab->first;

while(entry)

{

if(entry->name)

{

free(entry->name);

}

if(entry->val)

{

free(entry->val);

}

if(entry->func_body)

{

free_node_tree(entry->func_body);

}

struct symtab_entry_s *next = entry->next;

free(entry);

entry = next;

}

free(symtab);

}

我們稱 free_symtab() 當我們完成了符號表的工作后,我們想使用該函數,并希望釋放符號表及其條目所使用的內存。

接下來,我們將定義一個調試功能:

void dump_local_symtab(void)

{

struct symtab_s *symtab = symtab_stack.local_symtab;

int i = 0;

int indent = symtab->level * 4;

fprintf(stderr, "%*sSymbol table [Level %d]: ", indent, " ", symtab->level);

fprintf(stderr, "%*s=========================== ", indent, " ");

fprintf(stderr, "%*s No Symbol Val ", indent, " ");

fprintf(stderr, "%*s------ -------------------------------- ------------ ", indent, " ");

struct symtab_entry_s *entry = symtab->first;

while(entry)

{

fprintf(stderr, "%*s[%04d] %-32s '%s' ", indent, " ",

i++, entry->name, entry->val);

entry = entry->next;

}

fprintf(stderr, "%*s------ -------------------------------- ------------ ", indent, " ");

}

此功能打印本地符號表的內容。當我們的外殼啟動時,本地和全局符號表將引用同一表。只有在Shell要運行Shell函數或腳本文件時,我們的本地表才與全局表不同。(在本課程后面,我們將編寫一個內置實用程序,該實用程序將調用dump_local_symtab() 以幫助我們可視化外殼的全局符號表的內容)。

現在,讓我們定義一些函數來幫助我們處理符號表條目。在同一文件中(symtab.c),添加以下功能:

struct symtab_entry_s *add_to_symtab(char *symbol)

{

if(!symbol || symbol[0] == '

主站蜘蛛池模板: 亚洲精品国偷自产在线99人热 | 精品婷婷色一区二区三区 | 精品国精品国产自在久国产不卡 | 国产特级毛片aaaaaa毛片 | 337p日本欧洲亚洲大胆艺术图 | 虚拟VR一区二区三区 | 无码人妻一区二区三区线 | 国产裸体裸拍免费观看 | 玩弄放荡人妻少妇系列 | FREE性中国老太HD | 国产刺激高潮av | 四虎成人精品永久免费av | 欧美3| 人妻巨大乳挤奶水HD免费看 | 国产精品一区在线免费观看 | 视频久久免费 | 极品美女销魂一区二区 | 日本不卡高清一区二区三区 | 日产精品久久久久久久 | 中文字幕高清在线观看 | 亚洲中文在线精品国产 | 国产凹凸在线一区二区 | 男同GAY片AV网站猛男调教 | 亚洲一区二区三区成人网站 | 国产亚洲精品无码专区 | 超碰97人人做人人爱2020 | 脱了老师内裤猛烈进入的软件 | 中文字幕乱码免费视频 | 日本一区二区免费视频 | 久久天天躁狠狠躁夜夜躁2O2O | 天堂网在线WWW | 在线视频观看一区 | 在线天堂资源www在线中文 | 综合五月激情二区视频 | 久久久久香蕉国产线看观看伊 | 国产偷摄中国推油按摩富婆 | 国内精品自产拍在线观看 | 免费无码午夜福利片69 | 亚洲精品无码中文久久字幕 | 在线观看免费视频网站A站 九九99九九 | 色黄网站影院 |