问题描述
我正在脱壳,一个小的bash样壳,没有脚本(如果在......) 我必须用手制作lexer/parser(ll).
因此,Lexer将将命令( char * cmd )转换为链接列表( t_list * list ).
LL解析器将将链接列表(
所以,我知道如何制作LL解析器,但我不知道如何授权我的命令.
例如:ps | grep ls >> file ; make && ./a.out
=> 'ps' '|' 'grep' 'ls' '>>' 'file' ';' ''make '&&' './a.out'
谢谢.
(我不想使用任何发电机)
推荐答案
(这解释了由 spudd86 )暗示的想法.
您需要实现有限状态机.以下各州:
- 总态
- 在文件名 内部
- 在&&令牌中
- 在||令牌中
对于每个状态和下一个输入字符,您必须决定下一个状态是什么,以及是否输出令牌.例如:
- 当前状态:一般;字符: x =>下一个状态:内部文件名
- 当前状态:内部文件名;字符:空间 =>下一个州: general ;输出令牌
- 当前状态:内部文件名;字符:& =>下一个状态:里面 - && ;输出令牌
- 当前状态:内部 - && ;字符:& =>下一个州:一般;输出令牌
- 当前状态:内部 - && ;字符: x =>下一个州:一般;语法错误
- ...(ad nusyum)
弄清楚所有规则的乏味工作(当您必须调试结果代码时,乐趣开始),因此大多数人使用代码生成器来执行此操作.
编辑:一些代码(抱歉,如果语法搞砸了;我通常在c ++中编程)
enum state { STATE_GENERAL, STATE_IN_FILENAME, ... }; // Many characters are treated the same (e.g. 'x' and 'y') - so use categories enum character_category { CHAR_GENERAL, // can appear in filenames CHAR_WHITESPACE = ' ', CHAR_AMPERSAND = '&', CHAR_PIPE = '|', CHAR_EOF = EOF, ... }; character_category translate(int c) { switch (c) { case '&': return CHAR_AMPERSAND; case ' ': case '\t': case '\n': return CHAR_WHITESPACE; ... default: return CHAR_GENERAL; } } void do_stuff() { character_category cat; state current_state = STATE_GENERAL; state next_state; char token[100]; char token_length = 0; do { int c = getchar(); cat = translate(c); // The following implements a switch on 2 variables int selector = 1000 * current_state + cat; switch (selector) { case 1000 * STATE_GENERAL + CHAR_GENERAL: next_state = STATE_IN_FILENAME; token[token_length++] = c; // append a character to a filename token break; case 1000 * STATE_GENERAL + CHAR_WHITESPACE: next_state = STATE_GENERAL; // do nothing break; case 1000 * STATE_GENERAL + CHAR_PIPE: next_state = STATE_IN_OR_TOKEN; // the first char in '||' or just '|' break; // Much repetitive code already; define a macro for the case constants? // Have to cover all states and all character categories; good luck... case 1000 * STATE_IN_FILENAME + EOF: case 1000 * STATE_IN_FILENAME + CHAR_WHITESPACE: next_state = STATE_GENERAL; printf("Filename token: %s\n", token); break; default: printf("Bug\n"); // forgot one of the cases? } current_state = next_state; } while (cat != CHAR_EOF); }