If R is a regular language, is R³ = R o R o R also regular?

My understanding of a regular language is that a language, to be formal, can be represented by a DFA or NFA. To prove that a language is not regular, you can use the pumping scheme to get a contradiction.

I'm trying to find out if R³ or R o R o R is regular, even if R is regular.

My understanding of the definition of R o R is that it is a kind of transitive mapping of R?

And I think if RoR is regular then RoR is also regular, so I have to prove that RoR is regular, which really means I'm trying to prove that regular languages ​​are transitive?

I'm not sure how to do that because I'm a bit confused about how regular languages ​​and transitivity are related – since I've only worked with transitivity relationships.

Pushdown automata – Create a PDA to recognize a language with at least bs

I try to construct one 3-state Recognize PDA (I need to create a transition diagram for this question)

W = {w ∈ {a, b}^* | w contains at least as many as as bs}

My previous thought process was:

 1. Start off in q0 (q0 being an accept state)
 2. add a $ to the start of the stack (so you can see when the stack is empty), then transition to q1 (not an accept state).
 3. If you receive an a:
  - if there is an a at the top of the stack, push the a on.
  - if there is a b at the top of the stack, pop the b.
  - if there is nothing on the top of the stack, push the a on.
 4. If you receive a b:
  - if there is an a at the top of the stack, pop the a.
  - if there is a b at the top of the stack, push the b on.
  - if there is nothing on the top of the stack push the b on.
 5. Once there is no more input:
  - if there is a $ at the top of the stack, transition to q3 (q3 being an accept state) - this means there was an equal number of as and bs
  - if there is an a at the top of the stack, transition to q3 (q3 being an accept state) - this means there was more as than bs
  if there is a b at the top of the stack, it means there was more bs than as, and thus we stay in q2, which is not an accept state.

(I'm sorry if this is hard to understand, I'm not sure how to link these transition diagrams of the PDAs I've seen in some posts.) If anyone can tell me how to create one and in the post I want to be able to link the post, to be more understandable if needed)

I have a few questions:

  1. Is this approach right?
  2. Is it right to assume that the machine is smart enough to know that if there is no AB on top of the stack and I get an A, it will put the A on the stack (something like (q1, a, ε) ?) -> (q1, a) to cover both cases where a is at the top of the stack and also the case where the stack contains nothing))
  3. Do I have to press $ at the beginning of q0 after q1 in the transition diagram (I saw that this applies to all the PDAs on my lecture slide – why I think it is necessary to include all machines if necessary)? to that – why is not it just implied?)
  4. I'm alright to have 2 different scenarios to go to q2, right? Or would it be better to do something in Q1? When I arrive at the end of my queuing queue, I keep looking up until I get that, and then move on to Q2.

Sorry if anything is unclear – I'm not very familiar with PDAs and the way things are described – let me know if I need to clarify something.

Localization – How to graph a language

When I look at other products (not on the internet) that contain language-specific information, such as user guides and product packages that list ingredients and the like, recurring procedures are typically oval language codes (which may still be a country are) codes, small flags or the full name of the language.

As a user, I find that flags work best when it comes to the place Language Selection: When I see a flag from whatever country it comes from, it becomes clear that you can change the language there. I would suggest placing the language selector in the upper right corner or bottom left of the menu column – these are the places that are most commonly used and therefore the easiest to find.

As for sorting longer lists (and especially sorting by English names), I would suggest that you actually try to figure out what users find easiest. When you sort a list by English name, finding a language that does not start with the same letter is very difficult. (I can either interpret English or look at the different fonts, but not both.) This was also shown by the display of a word saying "red" in blue, so you can easily see one with a little more My suspicion that the exemplary list, while very clear and appealing, may not be the easiest to use.

Web Development – Language / Framework Recommendation

I do not know if this is the right place for this question, but …

I need to develop a simple (really simple) project that is based primarily on the user interface and the interaction, but it must work properly. My question is which language / framework do you recommend to create software (it can be mobile or just a site) that can register users who have a profile with some information and a page where users are Display 1 Type User Type 2.

I need a simple framework / language / API, I thought about using Javascript, responding or using Ruby on Rails. Do you have a better suggestion? Remember it
I will not do anything very complex.

Performance – User-defined function call on a stack-based interpreter for the chained language

I'd like some advice on how to improve a small chained stacks-based interpreter that runs a programming language that's fun. It's really minimal and indeed a subset of a larger version that should be used a priori as a compilation target.

The version I want to check here, however, is functional and representative of the base of the other. In short, I'd like to have global opinions on what should be improved or banned, and I'd also like to pay more attention to the way the interpreter manages function calls:

void evalfunc(Stack *stack, struct Function *function, struct Dico *dico)
{
    for (size_t i = 0; i < function->body.size; i++)
        evalop(stack, &function->body.array(i), dico);
}

In fact, I have the impression that being a way of doing things is rather rudimentary and does not allow you to recalculate infinitely as it uses the stack of the program; And since the term loop does not exist in this style of speech, there is only one recursion. I'm wondering if you could not do something to allow a feature like this:

undefined = undefined
forever   = doSomeStuff forever  // If we need to execute an entire program in an "infinite loop" for example, it would be really nice

not cause a stack overflow, even though the recursion limit is unreachable and sufficient most of the time. In a larger version of this project, programs to interpret are likely to perform operations as we would with a simple one while(true) Loop, and recursion is the only way to do it now; I do not want to have to implement something that goes beyond the philosophy of concatenated functional programming … but if there's no other way, let me know 🙂

So, here are the files and the Makefile (with GCC, compiled on Windows with mingw):

Makefile

CC = gcc
CCFLAGS = -g -W -Wall -Wno-missing-braces -O2 -Wno-unused-value

OBJS = Combinator.o Function.o Interpret.o RawCode.o Stack.o Show.o

all : main

main : ${OBJS} main.o
    @echo Linking...
    ${CC} ${CCFLAGS} ${OBJS} main.o -o main

Stack.o : Stack.c
    ${CC} ${CCFLAGS} -c Stack.c

Combinator.o : Combinator.c
    ${CC} ${CCFLAGS} -c Combinator.c

Function.o : Function.c
    ${CC} ${CCFLAGS} -c Function.c

Interpret.o : Interpret.c
    ${CC} ${CCFLAGS} -c Interpret.c

RawCode.o : RawCode.c
    ${CC} ${CCFLAGS} -c RawCode.c

Show.o : Show.c
    ${CC} ${CCFLAGS} -c Show.c

Combinator.h

#pragma once

enum Combinator
    { POP, DUP, SWAP
    , FLIP, ID, QUOTE
    , UNQUOTE, UNKNOWN };

static const char Str_Combs()(8) =
    { "pop", "dup", "swap"
    , "flip", "id", "quote"
    , "unquote" };

enum Combinator string_to_comb(const char*);

Combinator.c

#include 
#include "Combinator.h"

enum Combinator string_to_comb(const char *s)
{
    for (unsigned int i = 0; i < sizeof(Str_Combs) / sizeof(Str_Combs(0)); i++)
        if (!strcmp(Str_Combs(i), s))
            return (enum Combinator)i;
    return UNKNOWN;
}

Function.h

#pragma once
#include 

#include "RawCode.h"

struct Function
{
    char *name;
    RawCode body;
};

struct Dico
{
    struct Function *functions;
    size_t size;
    size_t used;
};

void init_dico(struct Dico *, size_t);
void push_dico(struct Dico *, struct Function);

struct Function make_Function(char *, RawCode);

struct Function *get_specific_function(char *, struct Dico *);

Function.c

#include 
#include 

#include "Function.h"
#include "RawCode.h"

void init_dico(struct Dico *dico, size_t size)
{
    dico->functions = (struct Function *)malloc(size * sizeof(struct Function));
    dico->used = 0;
    dico->size = size;
}

void push_dico(struct Dico *dico, struct Function function)
{
    if (dico->used == dico->size)
    {
        dico->size *= 2;
        dico->functions = (struct Function *)realloc(dico->functions, dico->size * sizeof(struct Function));
        if (dico->functions == NULL)
            perror("Out of vector memory");
    }
    dico->functions(dico->used++) = make_Function(function.name, function.body);
}

struct Function make_Function(char *name, RawCode body)
{
    return (struct Function){.name = name, .body = body};
}

struct Function *get_specific_function(char *name, struct Dico *dico)
{
    for (size_t i = 0; i < dico->used; i++)
        if (!strcmp(dico->functions(i).name, name))
            return &dico->functions(i);
    return NULL;
}

Interpret.h

#pragma once

#include 

#include "Stack.h"
#include "RawCode.h"
#include "Combinator.h"
#include "LiteralOperation.h"
#include "Function.h"

// Execute the code from RawCode and return the resulting stack
Stack interpret(RawCode, struct Dico);
// Evaluate the given operation on the stack
void evalop(Stack *, struct Value *, struct Dico *);
// Evaluate the given combinator on the stack
void evalcomb(Stack *, enum Combinator, struct Dico *);
// Evalute a word on the stack
void evalword(Stack *, struct Dico *, char *);
// Evaluate a function on the stack
void evalfunc(Stack *, struct Function *, struct Dico *);
// Evalute the given literal operation on the stack
void evallo(Stack *, enum LiteralOperation, struct Dico *);

Interpret.c

#include 
#include 
#include 

#include "Interpret.h"
#include "RawCode.h"
#include "Function.h"
#include "Stack.h"
#include "Combinator.h"
#include "LiteralOperation.h"

#include "Show.h"

Stack interpret(RawCode rcode, struct Dico dico)
{

    Stack runtime_stack;
    init_stack(&runtime_stack, rcode.used);

    for (size_t i = 0; i < rcode.used; i++)
        evalop(&runtime_stack, &rcode.array(i), &dico);

    return runtime_stack;
}

void evalop(Stack *stack, struct Value *value, struct Dico *dico)
{
    switch (value->kind)
    {
        // If the value is a quotation or any literal, then just push it on the stack
    case Val_Quotation ... Val_String:
        push(stack, *value);
        break;
        // If this is a stack combinator, then apply it on the stack
    case Val_Combinator:
        evalcomb(stack, value->u.comb_.comb, dico);
        break;
        // If this is a "word" (a function), then evaluate it
    case Val_Word:
        evalword(stack, dico, value->u.word_.word);
        break;
    case Val_LiteralOperation:
        evallo(stack, value->u.literalOperation_.literalOperation, dico);
        break;
    case Val_Empty:
        printf("Empty stack!n");
        break;
    }
}

void evalcomb(Stack *stack, enum Combinator comb, struct Dico *dico)
{
    switch (comb)
    {
    case POP:
        pop(stack);
        break;
    case DUP:
        push(stack, *top_ptr(stack));
        break;
    case SWAP:
    {
        struct Value tmp = *topx_ptr(stack, 1);
        *topx_ptr(stack, 1) = *topx_ptr(stack, 2);
        *topx_ptr(stack, 2) = tmp;
    }
    break;
    case FLIP:
    {
        struct Value tmp = *topx_ptr(stack, 1);
        *topx_ptr(stack, 1) = *topx_ptr(stack, 3);
        *topx_ptr(stack, 3) = tmp;
    }
    break;
    case ID:
        break;
    case QUOTE:
    {
        RawCode *quote = (RawCode *)malloc(sizeof(*quote));
        init_rcode(quote, 1);
        push_rcode(quote, *top_ptr(stack));
        *top_ptr(stack) = make_Val_Quotation(quote);
    }
    break;
    case UNQUOTE:
    {
        struct Value quote = drop(stack);

        for (size_t i = 0; i < quote.u.quote_.quote->used; i++)
            evalop(stack, "e.u.quote_.quote->array(i), dico);
    }
    break;
    case UNKNOWN:
    default:
        printf("Unknown combinator '%d'n", (int)comb);
    }
}

void evalfunc(Stack *stack, struct Function *function, struct Dico *dico)
{
    for (size_t i = 0; i < function->body.size; i++)
        evalop(stack, &function->body.array(i), dico);
}

void evalword(Stack *stack, struct Dico *dico, char *word)
{
    struct Function *tmptr_function = get_specific_function(word, dico);

    if (tmptr_function != NULL)
    {
        evalfunc(stack, tmptr_function, dico);
    }
    else if (!strcmp(word, "lowereq"))
    {
        // `x y lowereq` returns 1 or 0 depending on x is lower or equals to y
        evalcomb(stack, SWAP, dico);
        *top_ptr(stack) = make_Val_Integer((bool)(drop(stack).u.integer_.integer <= top(*stack).u.integer_.integer));
    }
    else if (!strcmp(word, "if"))
    {
        if ((bool)topx_ptr(stack, 3)->u.integer_.integer == true)
        {
            pop(stack);
            evalcomb(stack, SWAP, dico);
            pop(stack);
            evalcomb(stack, UNQUOTE, dico);
        }
        else
        {
            evalcomb(stack, SWAP, dico);
            pop(stack);
            evalcomb(stack, SWAP, dico);
            pop(stack);
            evalcomb(stack, UNQUOTE, dico);
        }
    }
    else
    {
        printf("Unknown word '%s'n", word);
    }
}

void evallo(Stack *stack, enum LiteralOperation lo, struct Dico *dico)
{
    // We have to swap the top of the stack for more logic:
    // `5 3 -`  will give 3 - 5 with the method below,
    // it's more logic for us to think that as `5 - 3`

    evalcomb(stack, SWAP, dico);

    switch (lo)
    {
    case ADD:
        push(stack, make_Val_Integer(drop(stack).u.integer_.integer + drop(stack).u.integer_.integer));
        break;
    case SUB:
        push(stack, make_Val_Integer(drop(stack).u.integer_.integer - drop(stack).u.integer_.integer));
        break;
    case MUL:
        push(stack, make_Val_Integer(drop(stack).u.integer_.integer * drop(stack).u.integer_.integer));
        break;
    case DIV:
        push(stack, make_Val_Integer(drop(stack).u.integer_.integer / drop(stack).u.integer_.integer));
        break;
    }
}

LiteralOperation.h

#pragma once

enum LiteralOperation
    { ADD, SUB, MUL, DIV };

RawCode.h

#pragma once
#include 

#include "Combinator.h"
#include "LiteralOperation.h"

typedef struct RawCode RawCode;
typedef enum Kind Kind;

struct Value {
    enum Kind
        { Val_Quotation, Val_Integer, Val_String, Val_Word, Val_LiteralOperation, Val_Combinator, Val_Empty } kind;
    union {
        // Quotation
        struct { RawCode* quote; } quote_;
        // Integer literal
        struct { int integer; } integer_;
        // Char literal
        struct { char character; } character_;
        // char* literal
        struct { char* string; } string_;
        // A stack combinator
        struct { enum Combinator comb; } comb_;
        // A word on the stack (a function)
        struct { char* word; } word_;
        // A literal operation (+, -, *, /)
        struct { enum LiteralOperation literalOperation; } literalOperation_;
    } u;
};

struct Value make_Val_Quotation(RawCode*);
struct Value make_Val_Integer(int);
struct Value make_Val_string(char*);
struct Value make_Val_Word(char*);
struct Value make_Val_LiteralOperation(enum LiteralOperation);
struct Value make_Val_Combinator(enum Combinator);

struct RawCode {
    struct Value* array;
    size_t used;
    size_t size;
};

void init_rcode(RawCode*, size_t);
void push_rcode(RawCode*, struct Value);
void pop_rcode(RawCode*);

struct Value drop_rcode(RawCode*);
struct Value top_rcode(RawCode);

// When the stack is empty
static const struct Value empty_value = { .kind = Val_Empty };

RawCode.c

#include 
#include 
#include 

#include "RawCode.h"
#include "Combinator.h"
#include "LiteralOperation.h"

struct Value make_Val_Quotation(RawCode *rcode)
{
    return (struct Value){.kind = Val_Quotation, .u = {.quote_ = rcode}};
}

struct Value make_Val_Integer(int x)
{
    return (struct Value){.kind = Val_Integer, .u = {.integer_ = x}};
}

struct Value make_Val_String(char *s)
{
    return (struct Value){.kind = Val_String, .u = {.string_ = s}};
}

struct Value make_Val_Word(char *s)
{
    return (struct Value){.kind = Val_Word, .u = {.word_ = s}};
}

struct Value make_Val_LiteralOperation(enum LiteralOperation lo)
{
    return (struct Value){.kind = Val_LiteralOperation, .u = {.literalOperation_ = lo}};
}

struct Value make_Val_Combinator(enum Combinator comb)
{
    return (struct Value){.kind = Val_Combinator, .u = {.comb_ = comb}};
}

void init_rcode(RawCode *rcode, size_t initSize)
{
    rcode->array = (struct Value *)malloc(initSize * sizeof(struct Value));
    rcode->used = 0;
    rcode->size = initSize;
}

void push_rcode(RawCode *rcode, struct Value item)
{
    if (rcode->used == rcode->size)
    {
        rcode->size *= 2;
        rcode->array = (struct Value *)realloc(rcode->array, rcode->size * sizeof(struct Value));
        if (rcode->array == NULL)
            perror("Out of raw code memory");
    }
    rcode->array(rcode->used++) = item;
}

void pop_rcode(RawCode *rcode)
{
    rcode->array(rcode->used--);
}

struct Value drop_rcode(RawCode *rcode)
{
    struct Value last = top_rcode(*rcode);
    pop_rcode(rcode);
    return last;
}

struct Value top_rcode(RawCode rcode)
{
    if (rcode.size == 0)
        return empty_value;
    return rcode.array(rcode.used - 1);
}

Show.h

#pragma once
#include "Stack.h"
#include "RawCode.h"
#include "Combinator.h"

char* showStack(Stack);
char* showValue(struct Value);
char* showLo(enum LiteralOperation);
char* showQuote(RawCode);
char* showComb(enum Combinator);

Show.c

#include 
#include 
#include 

#include "Stack.h"
#include "Show.h"
#include "RawCode.h"
#include "Combinator.h"

char *showValue(struct Value value)
{
    char *result;
    switch (value.kind)
    {
    case Val_Integer:
        __mingw_asprintf(&result, "%d", value.u.integer_.integer);
        break;
    case Val_String:
        __mingw_asprintf(&result, ""%s"", value.u.string_.string);
        break;
    case Val_Word:
        __mingw_asprintf(&result, "%s", value.u.word_.word);
        break;
    case Val_Quotation:
        __mingw_asprintf(&result, "%s", showQuote(*value.u.quote_.quote));
        break;
    case Val_Combinator:
        __mingw_asprintf(&result, "%s", showComb(value.u.comb_.comb));
        break;
    case Val_Empty:
        return ""; // 'empty-stack
    case Val_LiteralOperation:
        __mingw_asprintf(&result, showLo(value.u.literalOperation_.literalOperation));
        break;
    default:
        return "'Unknown";
    }
    return result;
}

char *showComb(enum Combinator comb)
{
    return (char *)Str_Combs((int)comb);
}

char *showLo(enum LiteralOperation lo)
{
    switch (lo)
    {
    case ADD:
        return "+";
    case SUB:
        return "-";
    case MUL:
        return "*";
    case DIV:
        return "/";
    }
    return "??";
}

char *showStack(Stack stack)
{
    char *result;
    __mingw_asprintf(&result, "( ");
    for (size_t i = 0; i < stack.used; i++)
    {
        if (stack.used >= 100 && i == 50)
        {
            i = stack.used - 1;
            __mingw_asprintf(&result, "%s (...) ", result);
        }
        __mingw_asprintf(&result, "%s%s ", result, showValue(stack.array(i)));
    }
    __mingw_asprintf(&result, "%s)", result);
    return result;
}

char *showQuote(RawCode rcode)
{
    if (rcode.used >= 50)
        return "(...)";
    char *result;
    __mingw_asprintf(&result, "(");
    for (size_t i = 0; i < rcode.used; i++)
    {
        if (rcode.used >= 100 && i == 50)
        {
            i = rcode.used - 1;
            __mingw_asprintf(&result, "%s (...) ", result);
        }
        __mingw_asprintf(&result, "%s%s ", result, showValue(rcode.array(i)));
    }
    __mingw_asprintf(&result, "%sb)", result);
    return result;
}

Stack.h

#pragma once

#include 
#include 

#include "RawCode.h"

typedef struct Stack
{
    struct Value *array;
    size_t used;
    size_t size;
} Stack;

void init_stack(Stack *, size_t);
// Adds an item to the top of the stack
void push(Stack *, struct Value);
// Removes the most recently added item
void pop(Stack *);
// Removes the most recently added item and returns it
struct Value drop(Stack *);
// Gets the last added item => the top of the stack
struct Value top(Stack);

struct Value *top_ptr(Stack *);
struct Value *topx_ptr(Stack *, const size_t);

Stack.c

#include 
#include 

#include "Stack.h"

void init_stack(Stack *stack, const size_t initSize)
{
    stack->array = (struct Value *)malloc(initSize * sizeof(struct Value));
    stack->used = 0;
    stack->size = initSize;
}

void push(Stack *stack, const struct Value item)
{
    if (stack->used == stack->size)
    {
        stack->size *= 2;
        stack->array = (struct Value *)realloc(stack->array, stack->size * sizeof(struct Value));
        if (stack->array == NULL)
            perror("Out of stack memory");
    }
    stack->array(stack->used++) = item;
}

void pop(Stack *stack)
{
    stack->array(stack->used == 0 ? 0 : stack->used--);
}

struct Value drop(Stack *stack)
{
    struct Value last = top(*stack);
    pop(stack);
    return last;
}

struct Value top(const Stack stack)
{
    return stack.used == 0 ? empty_value : stack.array(stack.used - 1);
}

struct Value *top_ptr(Stack *stack)
{
    return &stack->array(stack->used - 1);
}

struct Value *topx_ptr(Stack *stack, const size_t x)
{
    return &stack->array(stack->used - x);
}

Main c

#include 
#include 

#include "Interpret.h"
#include "RawCode.h"
#include "Function.h"
#include "Show.h"

// Define a function that just call itself
void _undefined(struct Dico *dico)
{
    RawCode body;
    init_rcode(&body, 1);
    push_rcode(&body, make_Val_Word("undefined"));

    push_dico(dico, make_Function("undefined", body));
}

// Define a function with a const value
void _const(struct Dico *dico)
{
    RawCode body;
    init_rcode(&body, 1);
    push_rcode(&body, make_Val_Integer(42));

    push_dico(dico, make_Function("const", body));
}

// Define the factorial function
void _fac(struct Dico *dico)
{
    // fac = dup 1 lowereq (pop 1) (dup -- fac *) if
    RawCode body;
    init_rcode(&body, 6);
    push_rcode(&body, make_Val_Combinator(DUP));
    push_rcode(&body, make_Val_Integer(1));
    push_rcode(&body, make_Val_Word("lowereq"));

    RawCode *if_true = (RawCode *)malloc(sizeof(*if_true));
    init_rcode(if_true, 2);
    push_rcode(if_true, make_Val_Combinator(POP));
    push_rcode(if_true, make_Val_Integer(1));

    RawCode *if_false = (RawCode *)malloc(sizeof(*if_false));
    init_rcode(if_false, 4);
    push_rcode(if_false, make_Val_Combinator(DUP));
    push_rcode(if_false, make_Val_Integer(1));
    push_rcode(if_false, make_Val_LiteralOperation(SUB));
    push_rcode(if_false, make_Val_Word("fac"));
    push_rcode(if_false, make_Val_LiteralOperation(MUL));

    push_rcode(&body, make_Val_Quotation(if_true));
    push_rcode(&body, make_Val_Quotation(if_false));
    push_rcode(&body, make_Val_Word("if"));

    push_dico(dico, make_Function("fac", body));
}

int main(void)
{
    struct Dico dico;
    RawCode rcode;

    init_dico(&dico, 1);
    init_rcode(&rcode, 1);

    _undefined(&dico);
    _fac(&dico);
    _const(&dico);

    push_rcode(&rcode, make_Val_Integer(4000));
    push_rcode(&rcode, make_Val_Word("fac"));

    // So now, the raw code is like     `5 fac`
    // The interpreter will interpret that and return 120

    Stack result = interpret(rcode, dico);

    printf("%sn", showStack(result));

    return 0;
}

PS: I use a MINGW-specific function in the Show.c File is it __mingw_asprintf, If there are compilation problems, it probably comes from there, so it needs to be removed.

PPS: Here is a link to download the files.