Hi again,
I am working on a small project which sort of resembles a makeshift programming language, in which if the user types "print" and then a value, the console will write the value, and not the string, for example, if I write Print "Hello", it will output the string "hello". It is sort of like a makeshift language that I want touse to teach the basics of programming, here is my code:

#include <iostream>
using namespace std;

int main (void)
{
string firstword, secondword;

cout<<"Input: ";
firstword = cin.get();
cin.ignore(1,' ');
secondword = cin.get();
if (firstword == "print")
{
    secondword = firstword + secondword;
    cout << secondword;
}
return 0;
}

Thankyou!

Okay! That works well! But now I am trying to make an equation sytem, with if the user in puts an equation, it will bring it out to him, but how do I make it so that it only operates if the first input is a number, I tried to use the ctype.h functions but with no luck, hee is my code:

#include <iostream>
#include <string>
#include <ctype.h>
using namespace std;
int main()
{
    string firstin;
    string secondin;
    string thirdin;
    int loop = 1;
    while (loop == 1)
    {
    cin >> firstin;
    cin >> secondin;
    if (firstin == "print")
    {
        cout << secondin << "\n";
    }
    //Below is the function I am having trouble with:
    if (isalnum(str firstin)) cout << "Works";
    }
    char q;
    cin >> q;
    return 0;
}

Also How would I do it in a way that a new string is declared when needed, but not here if not needed, (Example: Print Hello is two inputs, but 1 + 8 is three inputs? Thankyou so much for the help, and I apologise for my very simple questions.

with no luck,

Meaning what? Compiler error? Outputs wrong stuff? crashes the computer? Creates a black hole that sucks in the known universe?

What exactly is isalnum(str firstin) trying to do? What's str?

how do I make it so that it only operates if the first input is a number, I tried to use the ctype.h functions

If you want only a number, why are you using isalnum()? Does that work with only numbers?

Also How would I do it in a way that a new string is declared when needed, but not here if not needed, (Example: Print Hello is two inputs, but 1 + 8 is three inputs?

And 1+8 is one input. Read the entire input as a single string and look at each character to decide what was entered. It's called parsing.

Edited 4 Years Ago by WaltP

I am sorry for the hassle, but I just do not get what to do.. I tweaked it up a bit, but now whenever I try to input a number into firstin, the program crashes. Here is the code:

#include <iostream>
#include <string>
#include <ctype.h>
using namespace std;
int main()
{
    int i;
    string firstin;
    string secondin;
    string thirdin;
    int loop = 1;
    while (loop == 1)
    {
    cin >> firstin;
    cin >> secondin;
    if (firstin == "print")
    {
        cout << secondin << "\n";
    }
    //Below is the function I am having trouble with:
    if (isalnum(firstin[i])) cout << "Works";
    }
    char q;
    cin >> q;
    return 0;
}

Thankyou!

Hi Dasttann777, I have this code:

    #include <iostream>
    #include <string>
    #include <ctype.h>
    #include<conio.h>
    using namespace std;


    int main()

    {

    string word;
    string divword= "";
    char *car;

    int loop = 1;

    while (loop == 1){

    getline (cin,word);

    if (strncmp(word.c_str(),"print",5)==0){

    int a = 5;           

    while(word[a] == ' ')

    a++;

    for(int i=a; i<strlen(word.c_str());i++)

       divword = divword + word[i];     

    cout <<divword<< "\n";

         divword="";

    }

    else if (word == "Exit")
    exit(0);

    }

    getch();

    return 0;

}

It looks good, but I am getting the follorwing errors:
||=== Hunter Programming Langauge, Debug ===|
C:\Users\Computer 2\Desktop\Hunter Programming Langauge\main.cpp||In function 'int main()':|
C:\Users\Computer 2\Desktop\Hunter Programming Langauge\main.cpp|14|error: 'strncmp' was not declared in this scope|
C:\Users\Computer 2\Desktop\Hunter Programming Langauge\main.cpp|18|error: 'strlen' was not declared in this scope|
C:\Users\Computer 2\Desktop\Hunter Programming Langauge\main.cpp|24|error: 'exit' was not declared in this scope|
C:\Users\Computer 2\Desktop\Hunter Programming Langauge\main.cpp|10|warning: unused variable 'car'|
||=== Build finished: 3 errors, 1 warnings ===|
I use Codeblocks/MinGW if that helps.

include <ctype.h>

#include<conio.h>

have you added all of the includes he mentioned?

include<conio.h>

Don't include that non-standard hassle-prone header. The sooner you get away from using it, the sooner you can call yourself a real programmer. there are explanations why all over these forums.

Hello, Dastaan​​777, I am newbie to code blocks / MinGW, but the following code works fine on it. If you have a mistake, let me know.

    #include <iostream>
    #include <string.h>
    #include <stdlib.h>

    using namespace std;
    int main()
    {
    string word;
    string divword= "";
    int loop = 1;
    while (loop == 1){
    getline (cin,word);
    if (strncmp(word.c_str(),"print",5)==0){
    int a = 5;
    while(word[a] == ' ')
    a++;
    for(unsigned int i=a; i<strlen(word.c_str());i++)
    divword = divword + word[i];
    cout <<divword<< "\n";
    divword="";
    }
    else if (word == "Exit")
    exit(0);
    }

    return 0;
    }

Edited 4 Years Ago by Daxmark

Comments
On this forum we do not code answers for others. We help *them* find the answers by giving suggestions and tips.

I have to agree with WaltP; if you are writing a simple program that resembles a language interpreter, and it is capable of computing non-trivial equations of more than a fixed size, then you really are talking about writing an intepreter. You'll want to go the whole route of tokenizing and parsing the input, even if the input is supposed to be limited in scope.

I suggest you start out with a simple, ad-hoc tokenizer, something that can break a line of input into a series of discrete elements that can then be operated upon by an equally simple parser. Something like this should be a good start:

enum TOKEN_TYPE {TK_ERROR, TK_INTEGER, TK_PLUS, TK_MINUS, TK_MULT, TK_DIV, TK_PRINT, TK_IDENTIFIER};

struct Token 
{
   std::string value;
   TOKEN_TYPE type;
};

Token* get_next_token(std::istream& source) 
{
   char next_char;
   next_char = toupper(source.get());

   if (isalpha(next_char))
   {
       Token* id = get_identifier(source, next_char);
       if (id->value == "PRINT")
       {
           id->type = TK_PRINT;
       }

       return id;
   }
   else if (isnumeric(next_char))
   {
       return get_integer(source, next_char);
   }
   else
   {
       Token* op;
       op = new Token();
       op->value = next_char; 
       switch(next_char)
       {
        case '+':
            op->type = TK_PLUS;
            break;
        case '-':
            op->type = TK_MINUS;
            break;
        case '*':
            op->type = TK_MULT;
            break;
        case '/':
            op->type = TK_DIV;
            break;          
       }

       return op;
    }
}

Token* get_identifier(std::istream& source, char start_char)
{
    Token* id = new Token();

    id->value = start_char;

    while(true)
    {
        char next_char = toupper(source.get());

        if (isalphanum(next_char))
        {
            id->value += next_char;  // append the current char to the value string
        }
        else 
        {
            source.putback(next_char);
            break;
        }
    }
}

(N.B.: This is not tested code, it probably has some bugs in it.)

The rest of the tokenizer should be straightforward from this; the remaining functions are left as an exercise. If this seems like a lot of work, it is; but it is also probably a lot less work than a less systematic approach would be, in the long run.

Edited 4 Years Ago by Schol-R-LEA

If you are writing a simple program that resembles a language interpreter, and it is capable of computing non-trivial equations of more than a fixed size, then you really are talking about writing an intepreter. You'll want to go the whole route of tokenizing and parsing the input, even if the input is supposed to be limited in scope.

I agree with the above. Don't do everything from scratch though. Do yourself a favour and take a look at Boost.Spirit. Here's a minimal example:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

#include <iostream>
#include <sstream>
#include <string>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

template <typename Iterator>
struct interpreter_grammar : qi::grammar<Iterator, int(), ascii::space_type>
{
    interpreter_grammar() : interpreter_grammar::base_type(entry)
    {
        using namespace qi::labels;

        entry = math_expression [_val = 1] | print_math_expression [_val = 2] | print_expression [_val = 3];
        math_expression = term >> *( ('+' >> term) | ('-' >> term) );
        term = qi::double_ >> *( ('*' >> qi::double_) | ('/' >> qi::double_) );
        print_math_expression = qi::lexeme["print" >> qi::space] >> math_expression;
        print_expression = qi::lexeme["print" >> qi::space] >> +qi::char_;
    }

    qi::rule<Iterator, int(), ascii::space_type> entry;
    qi::rule<Iterator, ascii::space_type> print_expression,
        print_math_expression, math_expression, term;
};

double evalMathExpr(std::string expr)
{
    double operand1, operand2, result, number;
    char operation;

    std::stringstream buffer(expr + '#'), ssResult;

    buffer >> operand1;

    while (buffer >> operation)
    {
        switch(operation)
        {
            case '+': case '-': ssResult << operand1 << operation; buffer >> operand1; break;
            case '*': buffer >> operand2; operand1 *= operand2; break;
            case '/': buffer >> operand2; operand1 /= operand2; break;
            case '#': ssResult << operand1; break;
        }
    }

    std::stringstream buffer2(ssResult.str() + '#');

    buffer2 >> result;

    while (buffer2 >> operation >> number)
    {
        switch(operation)
        {
            case '+': result += number; break;
            case '-': result -= number; break;
        }
    }

    return result;
}

int main()
{
    using namespace std;

    cout << "type an expression... or empty line to quit\n\n";

    interpreter_grammar<string::const_iterator> my_grammar;

    string str;

    while (getline(cin, str))
    {
        if (str.empty()) break;

        int expr_type;

        string::const_iterator iter = str.begin();
        string::const_iterator end = str.end();

        bool r = phrase_parse(iter, end, my_grammar, ascii::space, expr_type);

        if (r && iter == end)
        {
            switch(expr_type)
            {
                case 1 : cout << evalMathExpr(str) << endl; break;
                case 2 : cout << evalMathExpr(str.substr(6, str.length() - 6)) << endl; break;
                case 3 : cout << str.substr(6, str.length() - 6) << endl; break;
            }
        }
        else cout << "invalid expression..." << endl;
    }

    return 0;
}

Usage example:

type an expression... or empty line to quit

1+2+3
6
print Hello, World!
Hello, World!
print 1+2*3
7
asdf
invalid expression...

I see that the OP is still following this thread, so, in case (s)he decides to take the boost approach, here's something (s)he might find useful, as the spirit documentation on building syntax trees is inadequate (IMO). Also, since that article uses an earlier version of spirit, here's an example using the current version.

Usage example:

type an expression... or empty line to quit

-(1+2)*(1+3)^2
-48
print "hello, world!"
hello, world!
print 1+2^3*5
41
print "1+2+3"
1+2+3
print "hi
invalid expression...
1+2*/3
invalid expression...

Edited 4 Years Ago by m4ster_r0shi

Don't do everything from scratch though. Do yourself a favour and take a look at Boost.Spirit.

I disagree.
1) Boost is unnecessary
2) It's better at the early stages of learning to do things by scratch*.
3) It's also non-standard...

When you change languages/systems, Boost may not be an option and if that's what you learned you are SOL and can't write the code.

Things like Boost are not for learning. They are used to make your life easier after you know what you are doing.

* and it's obvious Dasttann777 is still learning.

Edited 4 Years Ago by WaltP

Boost is unnecessary

Sure. Cars are unnecessary too, since we can walk. Joking aside, this is not a well formed statement. Boost consists of many different libraries and covers a wide range of uses. Some of these components are highly portable and extremely useful for any project (e.g. smart pointers). Why not use them?

It's better at the early stages of learning to do things by scratch

Sometimes it is. Sometimes it isn't. If you decide to start learning game programming, your first project should not be building a rendering engine from scratch. You'll first use an existing engine to draw and move shapes and sprites on the screen. Similarly, if you're interested in parsing, it's better to use an existing framework at first. If you do it from scratch, it'll probably take you a while before seeing a tangible result of your effort and this might act as an inhibitive factor to your learning experience.

It's also non-standard...

Again, you're putting everything in the same bag. Also, don't forget that part of boost is (was?) non-standard simply because the C++ standard is left behind. There are many languages that support lambas, regexes, threading... etc... out-of-the-box. C++ was not one of them until recently. And many of these things were taken from boost.

When you change languages/systems, Boost may not be an option and if that's what you learned you are SOL and can't write the code.

I really don't know what POS languages/systems you are talking about :D Regarding this particular example, if you're used to working with boost spirit, you won't have a problem working with Haskell's Parsec or Java's JParsec or python's pyparsing or Scala's standard parser combinators.

Things like Boost are not for learning.

I strongly disagree. You make an overgeneralization here. Once you reach a certain point, you can learn a hell lot by reading boost source code and seeing how things work under the hood.

This article has been dead for over six months. Start a new discussion instead.