本文共 12813 字,大约阅读时间需要 42 分钟。
init/tokenizer.cpp中next_token函数
6 int next_token(struct parse_state *state) 7 { 8 char *x = state->ptr; 9 char *s; 10 11 if (state->nexttoken) { 12 int t = state->nexttoken; 13 state->nexttoken = 0; 14 return t; 15 } 16 17 for (;;) { 18 switch (*x) { 19 case 0: 20 state->ptr = x; 21 return T_EOF; 22 case '\n': 23 x++; 24 state->ptr = x; 25 return T_NEWLINE; 26 case ' ': 27 case '\t': 28 case '\r': 29 x++; 30 continue; 31 case '#': 32 while (*x && (*x != '\n')) x++; 33 if (*x == '\n') { 34 state->ptr = x+1; 35 return T_NEWLINE; 36 } else { 37 state->ptr = x; 38 return T_EOF; 39 } 40 default: 41 goto text; 42 } 43 } 44 45 textdone: 46 state->ptr = x; 47 *s = 0; 48 return T_TEXT; 49 text: 50 state->text = s = x; 51 textresume: 52 for (;;) { 53 switch (*x) { 54 case 0: 55 goto textdone; 56 case ' ': 57 case '\t': 58 case '\r': 59 x++; 60 goto textdone; 61 case '\n': 62 state->nexttoken = T_NEWLINE; 63 x++; 64 goto textdone; 65 case '"': 66 x++; 67 for (;;) { 68 switch (*x) { 69 case 0: 70 /* unterminated quoted thing */ 71 state->ptr = x; 72 return T_EOF; 73 case '"': 74 x++; 75 goto textresume; 76 default: 77 *s++ = *x++; 78 } 79 } 80 break; 81 case '\\': 82 x++; 83 switch (*x) { 84 case 0: 85 goto textdone; 86 case 'n': 87 *s++ = '\n'; 88 break; 89 case 'r': 90 *s++ = '\r'; 91 break; 92 case 't': 93 *s++ = '\t'; 94 break; 95 case '\\': 96 *s++ = '\\'; 97 break; 98 case '\r': 99 /* \-> line continuation */ 100 if (x[1] != '\n') { 101 x++; 102 continue; 103 } 104 case '\n': 105 /* \ -> line continuation */ 106 state->line++; 107 x++; 108 /* eat any extra whitespace */ 109 while((*x == ' ') || (*x == '\t')) x++; 110 continue; 111 default: 112 /* unknown escape -- just copy */ 113 *s++ = *x++; 114 } 115 continue; 116 default: 117 *s++ = *x++; 118 } 119 } 120 return T_EOF; 121 }
next_token函数整体逻辑:把文件中所有内容保存到字符串str。
在17行到43行的第一个for循环处理逻辑: 从文本找到待处理字符串的第一个字符。 具体操作: 在字符串找到有用字符,则会进入text中,分割字符串,保存内容;如果遇到字符串中非有用字符是"#",继续在字符串str中轮询,直接遇到换行符(’\n’),或者轮询到结束符(EOF),分别在35行返回T_NEWLINE,或者在38行中返回return T_EOF;如果遇到空行"\n",则返回T_NEWLINE;如到’ ‘,’\t’,'r’等特殊字符继续向前轮询字符。在52行开始的第二个for循环:找到需要待处理字符串后一个字符(例如:空格、结束符号、换行)。
有个数据结构struct parse_state。
struct parse_state { char *ptr; ------>指向剩余字符串 char *text; ------>保存 int line; --->处理的行数 int nexttoken; ---->处理过的分割符 };
举个例子:处理如下配置文件。
配置文件内容如下,使用vim set list查看,$是转行符,^I是table,其他就是看见的空格。1 import /init.environ.rc$ 2 import /init.usb.rc$ 3 $ 4 on fs$ 5 ^Imount_all ./fstab.uml $ 6 $ 7 on early-init$ 8 # Set init and its forked children's oom_adj.$ 9 write /proc/1/oom_score_adj -1000$ 10 tom-init-rc$ 11 $ ~
处理流程:
1)调用next_token(),如果遇到注释语句,从31行处理,直接轮询到行末换行符(’\n’),并且从35行出。 2)调用next_token(),处理到第4行,第一个字符是’o’,运行到40行,goto text,state->text = s=x。因为x=‘o’,匹配116行的default的case,执行到 s++ = x++;则x=‘n’,然后再匹配116行的default的case,执行完s++ = x++;则x是空格,则匹配56行的case,运行textdone,然后在s后面加结束符,则state->text=“on”,返回T_TEXT。 3) 调用next_token(),处理字符串“fs”,因为s=’\n’(换行符),匹配到61行,执行state->nexttoken = T_NEWLINE;运行到textdone,运行后,则state->text=“on”,返回T_TEXT。 4)调用next_token(),运行到11行,返回T_NEWLINE,并且把state->nexttoken=0。这样完成1行数据的处理。
|转义字符| 意义 |ASCII码值(十进制)|
|–|--| | \n |换行(LF),将当前位置移到下一行开头 |010| | \r |回车(CR) ,将当前位置移到本行开头 |013| | \t |水平制表(HT) ( 跳到下一个TAB位置)|009|\r是回车(CR),将光标移动到行前.
#include#include int main(int argc, char* argv[]){ printf("ab c\n"); // 输出:ab c printf("\td\n"); // 输出: d printf("abc\rf\n"); // 输出:fbc char str1[20]="abc\rf"; printf("%x %x %x %x %x",str1[0],str1[1],str1[2],str1[3],str1[4]);//0x61 0x62 0x63 0xd 0x66 return 0;}
转载地址:http://xafab.baihongyu.com/