C语言中的图灵机实现

Posted

技术标签:

【中文标题】C语言中的图灵机实现【英文标题】:Turing Machine Implementation in C 【发布时间】:2012-02-29 11:28:00 【问题描述】:

我正在为我的形式语言理论课程学习图灵机,教授建议在以下algorithm上运行以详细查看“TM”背后的逻辑,但不起作用,当尝试编译告诉我以下错误。

C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c||In function `Tape* insert_tape(Tape*, Direction, char)':|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c|44|error: invalid conversion from `void*' to `Tape*'|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c||In function `Tape* create_tape(char*)':|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c|68|error: invalid conversion from `void*' to `Tape*'|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c||In function `Transition* get_transition(char*)':|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c|80|error: invalid conversion from `void*' to `Transition*'|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c||In function `List* insert_list(List*, char*)':|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c|93|error: invalid conversion from `void*' to `List*'|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c||In function `List* insert_list_transition(List*, Transition*)':|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c|105|error: invalid conversion from `void*' to `List*'|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c||In function `TM* createTM(char*)':|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c|166|error: invalid conversion from `void*' to `TM*'|
C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos\Downloads\Tarea3 Discretas\TM.c|167|error: invalid conversion from `void*' to `List*'|
||=== Build finished: 7 errors, 0 warnings ===|

代码如下:

/* This C file implements a Non-determinitic Pushdown Automata
 * author: Kevin Zhou
 * Computer Science and Electronics
 * University of Bristol
 * Date: 21st April 2010
 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct tapes 
    struct tapes *left;
    struct tapes *right;
    char content;
 Tape;

typedef enum  LEFT,RIGHT  Direction;

typedef struct transition 
    char current_state;
    char tape_symbol;
    char new_state;
    char new_tape_symbol;
    Direction dir;
 Transition;

typedef struct list 
    Transition *content;
    struct list *next;
 List;

typedef struct tm 
    char *input_alpha;
    char *input;
    char *tape_alpha;
    char start;
    char accept;
    char reject;
    List *transition;
 TM;

Tape *insert_tape(Tape *t, Direction dir, char c) 
    Tape *head = t;
    Tape *new1 = calloc(1,sizeof(Tape));;
    new1 -> content = c;
    if(dir == LEFT) 
        while(t->left != NULL) 
            t = t->left;
        
        new1->right = t;
        new1->left = NULL;
        t->left = new1;
        return new1;
    
    if(dir == RIGHT) 
        while(t->right != NULL) 
            t = t->right;
        
        new1->left = t;
        new1->right = NULL;
        t->right = new1;
    
    return head;


Tape *create_tape(char *input) 
    int i=1;
    Tape *t = calloc(1,sizeof(Tape));
    t->content = input[0];
    while(1) 
        if(input[i] == '\0') break;
        t = insert_tape(t,RIGHT,input[i]);
        i++;
    
    return t;


/* turn the input string into Transition fields */
Transition *get_transition(char *s) 
    Transition *t = calloc(1,sizeof(Transition));
    Direction dir;
    t->current_state = s[0];
    t->tape_symbol = s[1];
    t->new_state = s[2];
    t->new_tape_symbol = s[3];
    dir = (s[4]=='R')? RIGHT:LEFT;
    t->dir = dir;
    return t;


/* turn the string into transitions and add into list */
List *insert_list( List *l, char *elem ) 
    List *t = calloc(1,sizeof(List));
    List *head = l;
    while(l->next!=NULL)
        l = l->next;
    t->content = get_transition(elem);
    t->next = NULL;
    l->next = t;
    return head;


/* insert a transition into a list */
List *insert_list_transition( List *l, Transition *tr) 
    List *t = calloc(1,sizeof(List));
    List *head = l;
    while(l->next!=NULL)
        l = l->next;
    t->content = tr;
    t->next = NULL;
    l->next = t;
    return head;


void print_tape( Tape *t,char blank) 
    char c;
    while(1) 
        if(t->content != blank) break;
        t= t->right;
    
    while(1) 
        if(t==NULL) break;
        c = t->content;
        if(t->content != blank)
            putchar(c);
        t= t->right;
    
    putchar('\n');


void print_transition (Transition *t) 
    char s1[] = "Left";
    char s2[] = "Right";
    if(t==NULL) 
        printf("NULL Transfer");
        return;
    
    printf("current:%c tape:%c new state:%c new tape:%c direction %s\n",t->current_state,t->tape_symbol,t->new_state,t->new_tape_symbol,(t->dir == LEFT)?s1:s2);


/*test if the char c is in the string s */
int contains ( char c, char *s ) 
    int i=0;
    while(1) 
        if(c== s[i]) return 1;
        if(s[i] == '\0') return 0;
        i++;
    


/* test if the input is a valid input */
int is_valid_input( char *input_alpha, char *input ) 
    int i=0;
    char c;
    while(1) 
        c = input[i];
        if(c == '\0') break;
        if(!contains(c,input_alpha)) return 0;
        i++;
    
    return 1;


TM *createTM (char *input) 

    TM *m = calloc(1,sizeof(TM));
    List *tr = calloc(1,sizeof(List));
    char *buffer;
    /*read input alphabet of PDA*/
    buffer = strtok(input,":");
    if(buffer == NULL) 
        printf("Error in reading input alphabet!\n");
        exit(1);
    
    m->input_alpha = buffer;

    /*read tape alphabet*/
    buffer = strtok(NULL,":");

    if(buffer == NULL) 
        printf("Error in reading tape alphabet!\n");
        exit(1);
    
    m->tape_alpha = buffer;

    /*read input sequence*/
    buffer = strtok(NULL,":");
    if(buffer == NULL) 
        printf("Error in reading input sequence!\n");
        exit(1);
    

    if(!is_valid_input(m->input_alpha,buffer)) 
        printf("Error! Input contains some invalid characters that don't match the input alphabet!\n");
        exit(1);
    

    m->input = buffer;
    buffer = strtok(NULL,":");
    m->start = buffer[0];
    buffer = strtok(NULL,":");
    m->accept = buffer[0];
    buffer = strtok(NULL,":");
    m->reject = buffer[0];

    /*read tape transition*/
    while(1) 
        buffer = strtok(NULL,":");
        if(buffer == NULL) break;
        tr = insert_list(tr,buffer);
    

    m->transition = tr->next;
    return m;


Transition *find_transition(List * list,char state, char tape_symbol) 
    Transition *t;
    while(1) 
        if(list==NULL) return NULL;
        t = list -> content;
        if(t->current_state == state && t->tape_symbol == tape_symbol)
            return t;
        list = list->next;
    


Tape *move(Tape *t,Direction dir, char blank) 
    if(dir == LEFT) 
        if(t->left==NULL) 
            t = insert_tape(t,LEFT,blank);
        
        return t->left;
    
    if(dir == RIGHT) 
        if(t->right==NULL) 
            t = insert_tape(t,RIGHT,blank);
        
        return t->right;
    
    return NULL;


void simulate( TM *m ) 
    /* first symbol in input symbol used to represent the blank symbol */
    const char blank = m->tape_alpha[0];
    char current_state = m->start;
    Tape *tape = create_tape(m->input);
    Tape *current_tape = tape;
    char current_tape_symbol;
    Transition *current_transition;
    while(1) 
        if(current_state == m->accept) 
            printf("Accept\n");
            print_tape(tape,blank);
            break;
        
        if(current_state == m->reject) 
            printf("Reject\n");
            print_tape(tape,blank);
            break;
        
        current_tape_symbol = (current_tape==NULL||current_tape ->content == '\0')?blank:current_tape->content;
        current_transition = find_transition(m->transition,current_state,current_tape_symbol);
        current_state = current_transition -> new_state;
        current_tape -> content = current_transition -> new_tape_symbol;
        current_tape = move( current_tape, current_transition ->dir, blank);
    


int main(void) 
    char s[300];
    TM *p;
    scanf("%s",s);
    p = createTM(s);
    simulate(p);
    return 0;

为什么这个程序不起作用?

【问题讨论】:

你已经标记了这个C,并且评论说“这个C文件”,但是文件是.cpp,通常表示C++,第一个错误是抱怨new,它听起来像一个 C++ 问题。你读过错误吗?它们都有行号。转到产生错误的每一行,查看它,看看是否有任何错误。然后,将其简化为最简单的可编译代码,该代码会产生您无法解决的任何错误(或错误),并将其提供给我们。不要把你的整个程序丢给我们,然后说“修复它”,至少表明你已经付出了一些努力。 @Chris Luts 我将扩展名更改为 .c 但不起作用,甚至通过 new1 更改新的,但告诉我以下错误:C:\Documents and Settings\Melkhiah.EQUIPO01\Mis documentos \Downloads\Tarea3 Discretas\TM.c|44|错误:来自void*' to Tape*'的无效转换| @Melkhiah66:您仍在使用 C++ 编译器。下面汤姆的回答只对了一半——它还取决于你的编译器选项以及你如何称呼它。 @Melkhiah88:您(或 makefile/build 脚本)使用什么命令来调用编译器? 你应该如何接受输入字符串,我的意思是你的代码是否适用于诸如 aabb 之类的语言和适用于 1011011011 之类的二进制转换? 【参考方案1】:

代码被视为 C++,因为文件扩展名为 .cpp。将其更改为 .c ,它应该可以工作。这更容易(并且不太可能导致问题)然后开始修改源代码以使其与 C++ 兼容。

编辑:我假设正在使用的编译器是gcccl,它们根据文件扩展名检测语言。由于情况并非如此,因此您必须告诉我们您使用的是什么编译器(和选项)。

编辑 2: 为了让它与 C++ 编译器一起工作,您必须像 @whitelionV 建议的那样将 new 重命名为 new1 并强制转换所有 calloc() 返回像这样的适当类型的值:

44     Tape *new1 = (Tape*)calloc(1,sizeof(Tape));;
68     Tape *t = (Tape *)calloc(1,sizeof(Tape));
80     Transition *t = (Transition *)calloc(1,sizeof(Transition));
93     List *t = (List *)calloc(1,sizeof(List));
105    List *t = (List *)calloc(1,sizeof(List));
166    TM *m = (TM *)calloc(1,sizeof(TM));
167    List *tr = (List *)calloc(1,sizeof(List));

【讨论】:

@MichaelBurr 问题已更改(请参阅编辑 - 最初文件是 turing_machine.cpp)。 gcc 和 cl 都使用文件扩展名来确定它是 C 还是 C++。 @tom: gcc 不使用文件扩展名来确定它是 C 还是 C++。 gcc 是一个 C 编译器。 g++ 是一个 C++ 编译器,两者都是 Gnu Compiler Collection (GCC) 的一部分。 我对此进行了测试,gcc 绝对不会将 a.c 和 a.cpp 视为相同的。来自network-theory.co.uk/docs/gccintro/gccintro_54.html:“...gcc 在检测到 C++ 文件扩展名时实际上会编译 C++ 源代码,但无法链接生成的目标文件。” @Arafangion:GCC 不只是一个 C 编译器,GCC 可以编译 C 和 C++,以及更多特定前端;因此“编译器集合” @whitelionV:是的......我相信我提到过。确切地说,是 Gnu 编译器集合。【参考方案2】:

new 是 C++ 中的保留字,将变量名改为 new1 之类的。或者将文件名上的 .cpp 更改为 c。

【讨论】:

【参考方案3】:

提供的程序是 C 语言,但是,您使用 C++ 编译器进行编译。

用C再次编译,应该没问题。

【讨论】:

以上是关于C语言中的图灵机实现的主要内容,如果未能解决你的问题,请参考以下文章

图灵程序设计丛书 共多少本?

图灵社区 阅读 怎样在 Markdown 中使程序代码带上行号

手动实现一门图灵完备的编程语言——Brainfuck

手动实现一门图灵完备的编程语言——Brainfuck

最惨图灵奖得主?C语言之父开发UNIX系统,逝世的时间却没人知道...

图灵社区 阅读 为啥要选择Python语言实现机器学习算法