如何手工写(外壳)词[英] How to write a (shell) lexer by hand

本文是小编为大家收集整理的关于如何手工写(外壳)词的处理方法,想解了如何手工写(外壳)词的问题怎么解决?如何手工写(外壳)词问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我正在脱壳,一个小的bash样壳,没有脚本(如果在......) 我必须用手制作lexer/parser(ll).

因此,Lexer将将命令( char * cmd )转换为链接列表( t_list * list ). LL解析器将将链接列表( t_list * list )转换为AST(二进制树 t_btree * root ),其中 grammar

所以,我知道如何制作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);
}

本文地址:https://www.itbaoku.cn/post/359379.html