I was trying to create a special assembler that will run with a specific machine type. I was trying to compile the program, but got a linker error:
/usr/bin/ld: lexer.o: in function `Lexer::lex(std::__cxx11::basic_string, std::allocator >)':
lexer.cpp:(.text+0x2ee): undefined reference to `Lexer::isSpecial(char)'
collect2: error: ld returned 1 exit status
Screenshot here
I have 3 main files: lexer.h, lexer.cpp, sasm.cpp. Here's the code.
lexer.h:
#ifndef LEXER_H
#define LEXER_H
#include <iostream>
#include <vector>
// type definitions
typedef uint8_t byte;
typedef std::vector<std::string> strings;
enum State : byte {
START,
READCHAR,
READBLOCK,
SKIP,
DUMP,
COMMENT,
END
};
// Instructions definitions
#define ADD 0x40000001
#define SUB 0x40000002
#define TIME 0x40000003
#define DIVIDE 0x40000004
#define HALT 0x40000000
class Lexer {
private:
bool isSpace(char c);
bool isSpecial(char c);
bool isGroup(char c);
char end_char, beg_char;
public:
strings lex(std::string s);
};
#endif
lexer.cpp:
#include "lexer.h"
strings Lexer::lex(std::string s) {
strings strLst;
char lexEme[256];
int i = 0;
int j = 0;
State state = START;
int done = 0;
int len = s.length();
int balance = 0;
while (i < len) {
switch (state) {
case START:
if (isSpace(s[i])) {
state = SKIP;
} else if (isGroup(s[i])) {
if (s[i] == '"') {
lexEme[j] = s[i];
j++;
i++;
}
state = READBLOCK;
} else if (s[i] == '/' && s[i + 1] == '/') {
i += 2;
state = COMMENT;
} else {
state = READCHAR;
}
break;
case READCHAR:
if (isSpace(s[i])) {
state = DUMP;
} else if (s[i] == '\\') {
i += 2;
} else if (isGroup(s[i])) {
if (s[i] == '"') {
lexEme[j] = s[i];
j++;
i++;
}
state = READBLOCK;
} else if (isSpecial(s[i])) {
if (j == 0) {
lexEme[j] = s[i];
j++;
i++;
}
state = DUMP;
} else if (s[i] == '/' && s[i + 1] == '/') {
i += 2;
state = COMMENT;
} else {
lexEme[j] = s[i];
j++;
i++;
}
break;
case READBLOCK:
if (s[i] == beg_char && s[i] != '"') {
balance++;
lexEme[j] = s[i];
j++;
i++;
} else if (s[i] == end_char) {
balance--;
lexEme[j] = s[i];
j++;
i++;
if (balance <= 0) {
state = DUMP;
}
} else if (end_char == '"' && s[i] == '\\') {
// TODO: fix this to actually record the chars
i += 2;
} else {
lexEme[j] = s[i];
j++;
i++;
}
break;
case SKIP:
if (isSpace(s[i])) {
i++;
} else {
state = READCHAR;
}
break;
case DUMP:
if (j < 0) {
lexEme[j] = 0;
strLst.push_back(lexEme);
j = 0;
}
state = START;
break;
case COMMENT:
if (s[i] != '\n') {
i++;
} else {
state = READCHAR;
}
break;
case END:
i = len;
break;
}
}
if (j > 0) {
lexEme[j] = 0;
strLst.push_back(lexEme);
}
return strLst;
}
// This function allows us what a space is
bool Lexer::isSpace(char c) {
switch (c) {
case '\n':
case '\r':
case '\t':
case '\v':
case ' ':
case '\f':
return true;
default:
return false;
}
}
bool Lexer::isGroup(char c) {
beg_char = c;
switch (c) {
case '"':
end_char = '"';
return true;
case '(' :
end_char = ')';
return true;
case ')':
return true;
default:
return false;
}
}
bool isSpecial(char c) {
switch (c) {
case '[':
case ']':
return true;
default:
return false;
}
}
sasm.cpp:
#include <fstream>
#include "lexer.h"
typedef uint32_t i32;
using namespace std;
vector<i32> compile(strings s);
bool isInteger(string s);
bool isPrimitive(string s);
i32 mapToNumber(string s);
int main (int argc, char* argv[]) {
// Check for input errors
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <sasm-file>" << endl;
exit(1);
}
// Read input file
ifstream infile;
infile.open(argv[1]);
if (!infile.is_open()) {
cerr << argv[1] << ": file can't be found" << endl;
exit(1);
}
string line;
string contents;
while (getline(infile, line)) {
contents += line + "\n";
}
infile.close();
// Parse infile
Lexer lexer;
strings lexEmes = lexer.lex(contents);
// Compile binary
vector<i32> instructions = compile(lexEmes);
// Write instructions to file
ofstream ofile;
ofile.open("out.bin", ios::binary);
for (i32 i = 0; i < instructions.size(); i++) {
ofile.write(reinterpret_cast<char*>(&instructions[i]), sizeof(i32));
}
ofile.close();
return 0;
}
vector<i32> compile(strings s) {
vector<i32> instructions;
for (i32 i = 0; i < s.size(); i++) {
if (isInteger(s[i])) {
instructions.push_back(stoi(s[i]));
} else {
i32 instruction = mapToNumber(s[i]);
if (instruction != -1) {
instructions.push_back(instruction);
} else {
cerr << "\033[1;31m" << s[i] << "\033[0m Invalid instruction" << std::endl;
}
}
}
return instructions;
}
bool isInteger(string s) {
for (i32 i = 0; i < s.length(); i++) {
if (!isdigit(s[i])) {
return false;
}
}
return true;
}
i32 mapToNumber(string s) {
if (s == "+") {
return ADD;
} else if (s == "-") {
return SUB;
} else if (s == "*") {
return TIME;
} else if (s == "/") {
return DIVIDE;
}
return -1; // Invalid instruction
}
Thanks for your answers.
You are missing the class reference in the function definition.
bool Lexer::isSpecial(char c)
^^^^^^^
Related
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
using namespace std;
class Stack {
public:
string stack[100][1];
int size;
Stack() { size = 0; }
~Stack() {};
void push(string data) {
stack[size][0] = data;
size += 1;
}
bool empty() {
if (size == 0)
{
return true;
}
else
{
return false;
}
}
string pop() {
size -= 1;
return stack[size][0];
}
string top() {
if (empty())
cout << "Stack is empty";
return stack[size - 1][0];
}
};
int pre(char op)
{
switch (op)
{
case '(': case ')': return 0;
case '+': case '-': return 1;
case '*': case '/': return 2;
}
return -1;
}
vector<string> infix_to_postfix(const vector<string>& expr) {
vector<string> postfix;
string op;
Stack st;
for (int i = 0; i < expr.size(); i++) {
if (expr[i][0] == '+' || expr[i][0] == '-' || expr[i][0] == '*' || expr[i][0] == '/') {
while (!st.empty()) {
op = (st.top()[0]);
if (pre(expr[i][0]) <= pre(op[0]))
postfix.push_back(st.pop());
else break;
}
postfix.push_back(expr[i]);
}
else if (expr[i][0] == '(') {
st.push(expr[i]);
}
else if (expr[i][0] == ')') {
while (!st.empty()) {
op = st.pop();
if (op[0] == '(') break;
else {
postfix.push_back(op);
}
}
}
else {
postfix.push_back(expr[i]);
}
}
return postfix;
}
int main() {
auto expr = infix_to_postfix({ "(", "2", "+", "3", ")", "*", "7" });
for (auto& elem : expr)
{
std::cout << elem << ", ";
}
std::cout << "\n";
return 0;
}
This program is supposed to convert from infix to postfix but it is not producing the correct output. I'm expecting the output to be:
2, 3, +, 7, *,
but the output is
2, +, 3, *, 7,
You have two issues.
When handling an operator, after popping the lower precedence operators you need to push the new operator onto the stack rather than adding it to the result:
if (expr[i][0] == '+' || expr[i][0] == '-' || expr[i][0] == '*' || expr[i][0] == '/') {
while (!st.empty()) {
op = (st.top()[0]);
if (pre(expr[i][0]) <= pre(op[0]))
postfix.push_back(st.pop());
else break;
}
st.push(expr[i]);
}
At the end of the function you need to pop any remaining operators off the stack:
while (!st.empty())
{
postfix.push_back(st.pop());
}
return postfix;
I am stuck with the error "string subscript out of range".
After testing, I am pretty sure that it's because of this function, which is used for reading values in a file, but have no idea what's wrong:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string read(string value) {
ifstream input;
string line="", output="";
size_t pos;
bool a = true;
int i = 0;
input.open("pg_options.txt");
if (!input.is_open()) {
cout << "pg_options.txt missing.";
return "error";
}
while (getline(input, line)) { //get file lines
pos = line.find(value);
if (pos == string::npos) { //if value in line
while (a == true) {
if (line[i] == '=') { //after "="
i++;
break;
}
else {
i++;
}
}
for (i; line[i] != ' '; i++) {
output += line[i]; //put value to output
}
}
}
input.close();
return output;
}
pg_options.txt:
include_special_characters=true
include_upper_case=true
include_lower_case=true
include_numbers=true
digits=10
cout << read("digits") returns the error mentioned above.
Thank you for your comments. I solved this by editing the for loop:
string read(string value) {
ifstream input;
int olength;
string line = "", output = "";
size_t pos;
bool a = true;
int i = 0;
input.open("pg_options.txt");
if (!input.is_open()) {
cout << "pg_options.txt missing.";
return "error";
}
while (getline(input, line)) {
pos = line.find(value);
if (pos != string::npos) {
while (a == true) {
if (line[i] == '=') {
i++;
break;
}
else {
i++;
}
}
olength = line.length() - value.length() - 1;
for (int i2 = 0; i2 < olength; i2++) {
output += line[i];
i++;
}
}
}
input.close();
return output;
}
this is data structure (stack) question. in c++. (no use STL)
i want input Infix Formula file(txt, if there is not file, input is user's typing.)
and convert Postfix Formula, then caculate formula.
how can i input Postfix Formula in caculate fuction ?
i try make file and read file, but is not work. (i try change endl position(delete), also not work.)
ArrayStack.h
#include <iostream>
#include <cstdlib>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
inline void error(const char *message)
{
cout << message << endl;
exit(1);
}
const int MAX_STACK_SIZE = 20;
class ArrayStack
{
private:
int top;
int data[MAX_STACK_SIZE];
public:
ArrayStack()
{
top = -1;
}
~ArrayStack()
{
}
bool isEmpty()
{
return top == -1;
}
bool isFull()
{
return top == MAX_STACK_SIZE - 1;
}
void push(int e)
{
if (isFull())
error("스택 포화 에러");
data[++top] = e;
}
int pop()
{
if (isEmpty())
error("스택 공백 에러");
return data[top--];
}
int peek()
{
if (isEmpty())
error("스택 공백 에러");
return data[top];
}
void display()
{
printf("[스택 항목의 수 = %2d] ==> ", top + 1);
for (int i = 0; i < top; i++)
printf("<%2d>", data[i]);
printf("\n");
}
};
pg1_stack.cpp
#pragma warning(disable:4996)
#include "ArrayStack.h"
#include <string.h>
#include <fstream>
inline static int precedence(char op)
{
switch (op) {
case '(': case ')': return 0;
case '+': case '-': return 1;
case '*': case '/': return 2;
}
return -1;
}
void infixToPostfix(FILE *fp = stdin)
{
char c, op;
double val;
ArrayStack stack;
ofstream os;
os.open("stack_Data.txt");
while ((c = getc(fp)) != '\n')
{
if ('0' <= c && c <= '9')
{
ungetc(c, fp);
fscanf_s(fp, "%lf", &val);
printf("%4.1f ", val);
os << val;
}
else if (c == '(')
stack.push(c);
else if (c == ')')
{
while (!stack.isEmpty())
{
op = stack.pop();
if (op == '(') break;
else
printf("%c ", op);
os << op;
}
}
else if (c == '+' || c == '-' || c == '*' || c == '/')
{
while (!stack.isEmpty())
{
op = stack.peek();
if (precedence(c) <= precedence(op))
{
printf("%c ", op);
os << op;
stack.pop();
}
else break;
}
stack.push(c);
}
}
while (!stack.isEmpty()) {
char c2 = stack.pop();
os << c2;
printf("%c ", c2);
}os << endl;
os.close();
printf("\n");
}
double calcPostfixExpr(const char *filename)
{
FILE *fp = fopen(filename, "r");
if (fp == NULL)
error("Error: 파일 존재하지 않습니다.\n");
char ch;
ArrayStack stack;
while ((ch = getc(fp)) != '\n')
{
if (ch == '+' || ch == '-' || ch == '*' || ch == '/')
{
double right = stack.pop();
double left = stack.pop();
switch (ch) {
case '+':
stack.push(left + right);
break;
case '-':
stack.push(left - right);
break;
case '*':
stack.push(left * right);
break;
case '/':
stack.push(left / right);
break;
}
}
else if ('0' <= ch && ch <= '9')
{
ungetc(ch, fp);
double val;
fscanf_s(fp, "%lf", &val);
stack.push(val);
}
}
fclose(fp);
return stack.pop();
}
void main() {
infixToPostfix();
double res = calcPostfixExpr("stack_Data.txt");
printf("%f", res);
system("Pause");
}
this is before try make file and read file way
#pragma warning(disable:4996)
#include "ArrayStack.h"
#include <string.h>
#include <fstream>
inline static int precedence(char op)
{
switch (op) {
case '(': case ')': return 0;
case '+': case '-': return 1;
case '*': case '/': return 2;
}
return -1;
}
void infixToPostfix(FILE *fp = stdin)
{
char c, op;
double val;
ArrayStack stack;
while ((c = getc(fp)) != '\n')
{
if ('0' <= c && c <= '9')
{
ungetc(c, fp);
fscanf_s(fp, "%lf", &val);
printf("%4.1f ", val);
}
else if (c == '(')
stack.push(c);
else if (c == ')')
{
while (!stack.isEmpty())
{
op = stack.pop();
if (op == '(') break;
else
printf("%c ", op);
}
}
else if (c == '+' || c == '-' || c == '*' || c == '/')
{
while (!stack.isEmpty())
{
op = stack.peek();
if (precedence(c) <= precedence(op))
{
printf("%c ", op);
stack.pop();
}
else break;
}
stack.push(c);
}
}
while (!stack.isEmpty()) {
char c2 = stack.pop();
printf("%c ", c2);
}
printf("\n");
}
double calcPostfixExpr(FILE* fp = stdin)
{
char ch;
ArrayStack stack;
while ((ch = getc(fp)) != '\n')
{
if (ch == '+' || ch == '-' || ch == '*' || ch == '/')
{
double right = stack.pop();
double left = stack.pop();
switch (ch) {
case '+':
stack.push(left + right);
break;
case '-':
stack.push(left - right);
break;
case '*':
stack.push(left * right);
break;
case '/':
stack.push(left / right);
break;
}
}
else if ('0' <= ch && ch <= '9')
{
ungetc(ch, fp);
double val;
fscanf_s(fp, "%lf", &val);
stack.push(val);
}
}
return stack.pop();
}
void main() {
infixToPostfix();
system("Pause");
}
I am getting a segmentation fault when trying to convert an infix expression into prefix order. I have a postfix using the same logic that works fine the issue seems to be where i try to read the infix expression in reverse but I am not exactly sure why it is faulting. Any help would greatly appreciated Here is the relevant code:
int ParseTree::prefix(string infix)
{
vector<string> exp;
stringstream ss(infix);
string tok;
while(getline(ss,tok,' '))
{
exp.push_back(tok);
}
vector<string> prefix;
stack<string> s;
for(unsigned int i = exp.size() - 1; i >= 0 ; i--)
{
if(parseTry(exp[i]))
{
prefix.push_back(exp[i]);
}
if(exp[i] == "(")
{
s.push(exp[i]);
}
if(exp[i] == ")")
{
while(!s.empty() && s.top() != "(")
{
prefix.push_back(s.top());
s.pop();
}
s.pop();
}
if(isOperator(exp[i]) == true)
{
while(!s.empty() && priority(s.top()) >= priority(exp[i]))
{
prefix.push_back(s.top());
s.pop();
}
s.push(exp[i]);
}
}
while(!s.empty())
{
prefix.push_back(s.top());
s.pop();
}
for(unsigned int i = 0; i < prefix.size(); i++)
{
cout << prefix[i] << " ";
}
return 0;
}
int ParseTree::priority(const string &s)
{
if(s == "*" || s == "/")
{
return 2;
}
if(s == "+" || s == "-")
{
return 1;
}
else
{
return 0;
}
}
bool ParseTree::parseTry(const string &s)
{
bool number = false;
for(unsigned int i = 0; i < s.size(); i++)
{
if(!isdigit(s[i]))
{
number = false;
}
else
{
number = true;
}
}
return number;
}
bool ParseTree::isOperator(const string &s)
{
return (s == "+" || s == "-" || s == "*" || s == "/");
}
So here's my problem:
I'm supposed to write a c++ program that checks a string to be balanced. So far I have the code working to make sure that it has the same number of ('s and )'s (the same with ['s and {'s). The problem is that this works for almost everything, but it doesn't work for strings where the {'s, ('s and ['s all get mixed up.
For example: "{ { [ ( ) ] } ( ) }" comes back as balanced (true) as it should. However, "{ ( [ ] } )" comes back true, but it shouldn't.
What are some ideas in the logic and/or code that would check for when they're out of order?
Thanks for any help!
In case it helps, my code follows:
bool ExpressionManager::isBalanced(string expression)
{
//remove whitespace
string edited;
for(int i = 0; i < expression.length(); i++)
{
if(expression[i] == ' ')
{
continue;
}
else
{
edited += expression[i];
}
}
expression = edited;
//set up brckets
string brackets;
for(int i = 0; i < expression.length(); i++)
{
if (expression.at(i)=='(')
{
brackets += expression.at(i);
}
if (expression.at(i)=='[')
{
brackets += expression.at(i);
}
if (expression.at(i)=='{')
{
brackets += expression.at(i);
}
if (expression.at(i)=='}')
{
brackets += expression.at(i);
}
if (expression.at(i)==']')
{
brackets += expression.at(i);
}
if (expression.at(i)==')')
{
brackets += expression.at(i);
}
}
int parenbal = 0;
int brackbal = 0;
int mustachebal = 0;
for (int i = 0; i<(brackets.size());i++)
{
if(brackets[i]=='(')
parenbal++;
if(brackets[i]=='[')
brackbal++;
if(brackets[i]=='{')
mustachebal++;
if(brackets[i]==')')
parenbal--;
if(brackets[i]==']')
brackbal--;
if(brackets[i]=='}')
mustachebal--;
}
bool isbalanced = false;
if ((mustachebal==0)&&(brackbal==0)&&(parenbal==0))
{
isbalanced = true;
}
//check for brackets mixed up with other stuff.
return isbalanced;
}
If you employ a Stack to store those tokens, then you are always looking for the closing-counterpart corresponding to the one on the top of the stack or an open-token.
The flow would be
If the token is an open token, push it onto the stack.
If the token is a close token, check if the top of the stack is the corresponding open-token. If it is, then pop the stack as you found them balanced. If it is not, then it's an error.
Seems more like a homework assignment. So I would comment accordingly and allow you to learn a few things.
Always initialize your variables. strings are not initialized in your code.
You do not iterate over the string three time, you can check the string only once.
Use if-else if-else structure instead of if-if-if structure.
Always use brackets braces
Be consistent with your usage, either use at() or [], but dont mix them in code.
//this code may help you check string for balanced brackets with no
//repeated brackets,paranthesis or braces (e.g. [2*{3/(1+2)}].Note: no repeatance of
//brackets
#include <iostream.h>
#include <conio.h>
#include "IntStack.h"
#include <stdio.h>
void main(void)
{
char bracket[20];
gets (bracket);
char arr[6];
int i=0;
while(i<20)
{
switch(bracket[i])
{
case '[':
{
arr[0]=1;
break;
}
case '{':
{
arr[1]=2;
break;
}
case '(':
{
arr[2]=3;
break;
}
case ')':
{
arr[3]=3;
break;
}
case '}':
{
arr[4]=2;
break;
}
case ']':
{
arr[5]=1;
break;
}
default:
cout<<"";
}
i++;
}
if(arr[3]==arr[2])
cout<<"";
else
cout<<" ) or ( is missing "<<endl;
if(arr[1]==arr[4])
cout<<"";
else
cout<<" } or { is missing "<<endl;
if(arr[5]==arr[0])
cout<<"";
else
cout<<" ] or [ is missing"<<endl;
}
void check_brackets (string bituy)
{
int flag = 1
int count[6] = {0, 0, 0, 0, 0, 0};
stack<char> barstack;
for (int i = 0; i < bituy.length(); i++)
{
if (bituy[i] == '{')
count[0]++;
else if (bituy[i] == '}')
count[1]++;
else if (bituy[i] == '(')
count[2]++;
else if (bituy[i] == ')')
count[3]++;
else if (bituy[i] == '[')
count[4]++;
else if (bituy[i] == ']')
count[5]++;
}
for (int i = 0; i < 6; i += 2)
{
if (count[i] != count[i+1])
{
cout << "Wrong Syntax!" << endl;
flag = 0;
break;
}
}
if (flag)
{
for (int i = 0; i < bituy.length(); i++)
{
if (bituy[i] == '{' || bituy[i] == '(' || bituy[i] == '[')
barstack.push(bituy[i]);
else
{
if ((barstack.top() == '{' && bituy[i] == '}') || (barstack.top() == '(' && bituy[i] == ')') || (barstack.top() == '[' && bituy[i] == ']'))
barstack.pop();
else
{
cout << "Wrong Syntax!" << endl;
flag = 0;
break;
}
}
}
}
if (flag)
cout << "No Errors!" << endl;
}
#include<bits/stdc++.h>
using namespace std;
bool isBalance(char n[],int size){
int i,count=0;
//int size=strlen(n);
for(i=0;i<size;i++){
if(n[i]=='{'||n[i]=='['||n[i]=='('){
count ++;
}
else if(n[i]=='}'||n[i]==']'||n[i]==')'){
count --;
}
else return -1;
}
if(count==0)
return true;
else
return false;
}
int main(){
char n[1000];
gets(n);
int size=strlen(n);
bool result=isBalance(n,size);
if(result==true)
cout<<"Balance";
else
cout<<"Not Balance";
return 0;
}
//bracket Chaecker program
void bracket_checker()
{
int i=0;
char d;
char ch;
int count=0;
char *s = new char[21];
fstream out;
out.open("brace.txt",ios::in);
while(out>>d)
{
if(d =='}'|| d ==')' || d == '{' || d =='(')
{
s[i]=d;
i++;
}
}
if (i % 2 != 0)
cout <<"\ninvalid braces";
else if (( s[0] == '}' || s[0]==')' || s[0]==']') || (s[i]=='{' || s[i]=='(' || s[i]=='[' ))
cout <<"\n invalid braces";
else
{
for(int a=0; a<i; a++)
{
if (s[a] == '(' || s[a] == '{' || s[a] =='[' )
push1(s[a]);
if((s[a]=='(' && (s[a+1]=='{' || s[a+1]=='}')) || (s[a]=='[' && (s[a+1]=='{' || s[a+1]=='}')))
break;
else
if (s[a] == ')' || s[a] == '}' )
{
if (head != NULL)
{
ch = pop1();
if( ch == '{' && s[a] == '}' || ch == '(' && s[a] == ')' || ch=='[' && s[a]==']')
cout <<" ";
else
break;
}
else
break;
}
}
if(head==NULL)
cout <<" valid";
else
cout <<"In Valid";
}
}