Witam!
Mam do uzupełenienia na zajęcia kod wirtualnej maszyny. Wszystko fajnie tylko pojawia się problem przy kompilacji. Wygląda następująco:
g++ -g -Wall -c -o analyzer.o analyzer.cpp
analyzer.cpp: In function ?const char* get_double(const char*, double&)?:
analyzer.cpp:182: error: ?strtod? was not declared in this scope
analyzer.cpp: In function ?const char* gettoken(const char*, tokentype&, tokenval&)?:
analyzer.cpp:227: error: ?errno? was not declared in this scope
analyzer.cpp:228: error: ?strtoll? was not declared in this scope
analyzer.cpp: In function ?const char* extract_address(const char*, argaddr&, bool)?:
analyzer.cpp:310: error: ?INT_MIN? was not declared in this scope
analyzer.cpp:310: error: ?INT_MAX? was not declared in this scope
analyzer.cpp:333: error: ?INT_MIN? was not declared in this scope
analyzer.cpp:333: error: ?INT_MAX? was not declared in this scope
make: *** [analyzer.o] Error 1
Byłabym wdzięczna gdyby mógł ktoś wyjaśnić dlaczego pojawiają się te błędy skoro wg mnie wszystko gra (ale pewnie się mylę)
Przedstawiam poniżej kod jednego z plików:
#include <ctype.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <errno.h>
using namespace std;
#include "vm.h"
unsigned int pass;
map < string, opcode > opcode_table;
/*
* Instruction format:
* add.i #bp+7, 7, *bp-6
* immediate direct indirect
* call #183
*/
//tablica instrukcji,struktury typu opcode_info
struct opcode_info opcodes[] = {
{"", OC_NONE, AT_NONE, h_none, s_none},
{"mov", OC_MOV, AT_NONE, h_mov, s_twoarg},
{"add", OC_ADD, AT_NONE, h_add, s_threearg},
{"sub", OC_SUB, AT_NONE, h_sub, s_threearg},
{"mul", OC_MUL, AT_NONE, h_mul, s_threearg},
{"mod", OC_MOD, AT_INTEGER, h_mod, s_threearg},
{"div", OC_DIV, AT_INTEGER, h_div, s_threearg},
{"and", OC_AND, AT_NONE, h_and, s_threearg},
{"or", OC_OR, AT_NONE, h_or, s_threearg},
{"call", OC_CALL, AT_INTEGER, h_call, s_oneinteger},
{"enter", OC_ENTER, AT_INTEGER, h_enter, s_oneinteger},
{"leave", OC_LEAVE, AT_INTEGER, h_leave, s_none},
{"return", OC_RETURN, AT_INTEGER, h_return, s_none},
{"write", OC_WRITE, AT_NONE, h_write, s_onearg},
{"read", OC_READ, AT_NONE, h_read, s_onearg},
{"jump", OC_JUMP, AT_INTEGER, h_jump, s_oneinteger},
{"je", OC_JE, AT_NONE, h_je, s_threearg_jump},
{"jge", OC_JGE, AT_NONE, h_jge, s_threearg_jump},
{"jg", OC_JG, AT_NONE, h_jg, s_threearg_jump},
{"jl", OC_JL, AT_NONE, h_jl, s_threearg_jump},
{"jle", OC_JLE, AT_NONE, h_jle, s_threearg_jump},
{"inttoreal", OC_INTTOREAL, AT_INTEGER, h_inttoreal, s_twoarg},
{"realtoint", OC_REALTOINT, AT_REAL, h_realtoint, s_twoarg},
{"push", OC_PUSH, AT_NONE, h_push, s_onearg},
{"incsp", OC_INCSP, AT_INTEGER, h_incsp, s_oneinteger},
{"exit", OC_EXIT, AT_INTEGER, h_none, s_none},
};
vector <void (*) (const instruction &) >dispatch_table(OC_FINAL);
vector <void (*) (const instruction &) >syntax_table(OC_FINAL);
vector <argtype > default_argtype_table(OC_FINAL);
void
setup_opcodes ()
{
for (unsigned int i = 0; i < sizeof (opcodes) / sizeof (opcodes[0]); i++)
{
opcode_table[opcodes[i].name] = opcodes[i].oc;
dispatch_table[opcodes[i].oc] = opcodes[i].oh;
syntax_table[opcodes[i].oc] = opcodes[i].sh;
default_argtype_table[opcodes[i].oc] = opcodes[i].at;
};
};
vector < instruction > instructions;
map < string, UINT >symtab;
UINT current_address = 0;
#define skipws(s) do {while (isspace(*(s))) (s)++;} while (0)
/*
* Read the label from the input line s
* Label is empty, if there's no label in the line
* Return the pointer to the first character after the label
* Syntax_error exception is thrown in case of syntax error
*/
const char *
extract_label (const char *s, string & label)
{
const char *os = s;
label.assign ("");
skipws (s);
const char *begword = s;
while (isalnum (*s))
s++;
const char *endword = s;
skipws (s);
if (*s == ':') //we have a label
{
if (endword == begword)
throw syntax_error ("Empty label");
if (!isalpha (*begword))
throw syntax_error ("Label starting with number");
label.assign (begword, endword);
if(label=="bp")
throw syntax_error("Reserved word: 'bp' used as a label");
return s + 1;
}
return os;
}
/*
* Read the opcode and operand size from the input line s
* It is assumed, that the label is removed from s
* Return the pointer to the first non-ws character
* after the opcode and operand size modifier
* Syntax_error exception is thrown in case of syntax error
*/
const char *
extract_instr (const char *s, opcode & oc, argtype & at)
{
at = AT_NONE;
oc = OC_NONE;
skipws (s);
const char *begword = s;
while (isalpha (*s))
s++;
const char *endword = s;
skipws (s);
if (begword == endword)
return s;
string op (begword, endword);
map < string, opcode >::iterator oi;
if ((oi = opcode_table.find (op)) == opcode_table.end ())
throw syntax_error ("Unknown opcode");
oc = oi->second;
if(oc>=OC_FINAL)
throw("Internal error: invalid opcode");
at = default_argtype_table[oc];
if (*s == '.') //we have reached the end of an opcode
{
s++;
skipws (s);
if (*s == 'r')
at = AT_REAL;
else if (*s == 'i')
at = AT_INTEGER;
else
throw syntax_error ("Unknown operand type specifier");
s++;
};
skipws (s);
return s;
};
/*
* Lookup a label in the symbol table
* Return -1 if symbol not present
*/
long long
lookup (const string & val)
{
map < string, UINT >::iterator i;
i = symtab.find (val);
if (i == symtab.end ())
return -1;
else
return i->second;
}
/*
* Get double literal from input line.
* Skip leading and trailing whitespace.
* Throw exception if number nonexistent or misformed.
*/
const char *
get_double (const char *s, double &d)
{
char *ns;
d = strtod (s, &ns);
if (s != ns)
s = ns;
else
throw syntax_error ("Real literal not found or misformed");
skipws (s);
return s;
};
bool
issep (char c)
{
if ((c == ',') || (c == '\0'))
return true;
else
return false;
};
enum tokentype
{ TT_CHAR, TT_INTEGER, TT_ID, TT_NONE };
struct tokenval
{
string s;
union
{
long long i;
char c;
};
};
/*
* Get next token from string s
* Skip leading and trailing whitespace
* Return pointer to the next non-ws character in s after the token
*/
const char *
gettoken (const char *s, tokentype & token, tokenval & val)
{
skipws (s);
if (isdigit (*s) || (*s == '+') || (*s == '-'))
{
char *ns;
errno=0;
long long v=strtoll(s, &ns, 0);
if ((errno!=0) || (ns == s))
{
//not a number
val.c = *s;
token = TT_CHAR;
skipws (s);
return s;
};
val.i = v;
s = ns;
skipws (s);
token = TT_INTEGER;
return s;
}
if (isalpha (*s))
{
const char *begin = s;
while (isalnum (*s))
s++;
val.s.assign (begin, s);
skipws (s);
token = TT_ID;
return s;
};
if (issep (*s))
{
token = TT_NONE;
return s;
}
val.c = *s;
token = TT_CHAR;
skipws (s);
return s;
};
/*
* Read the argument from the input line s
* It is assumed, that we are after the separator
* Return the pointer to the separator after the operand
* Syntax_error exception is thrown in case of syntax error
* Realmode indicates, whether the operand type
* is real (true) or integer (false)
*/
const char *
extract_address (const char *s, argaddr & aa, bool realmode)
{
aa.am = AM_DIRECT;
aa.br = BR_NONE;
skipws (s);
if (*s == '#')
{
aa.am = AM_IMMEDIATE;
s++;
}
else if (*s == '*')
{
aa.am = AM_INDIRECT;
s++;
}
skipws (s);
/*
* Acceptable address formats:
* bp
* bp + number
* bp - number
* int_number
* real_number (only iff realmode==true and immediate mode used)
* label
*/
if ((aa.am == AM_IMMEDIATE) && realmode)
{
s = get_double (s, aa.realval);
if (!issep (*s))
throw syntax_error ("Garbage after real literal");
return s;
}
tokentype tt;
tokenval tv;
s = gettoken (s, tt, tv);
if (tt == TT_INTEGER)
{
if((tv.i<IMIN) || (tv.i>IMAX))
throw syntax_error("Number too big");
aa.intval = tv.i;
if (!issep (*s))
throw syntax_error ("Garbage after literal");
return s;
}
if (tt == TT_ID)
{
if (tv.s == "bp")
{
aa.br = BR_BP;
if ((*s == '+') || (*s == '-'))
{
int mult = (*s == '+') ? 1 : -1;
s++;
skipws(s);
if ((*s=='+') || (*s=='-'))
throw syntax_error("Duplicate sign after 'bp +/-'");
s = gettoken (s, tt, tv);
if (tt == TT_INTEGER)
{
long long t=tv.i*mult;
if((t<IMIN) || (t>IMAX))
throw syntax_error("Number too big");
aa.intval = t;
if (!issep (*s))
{
throw syntax_error ("Garbage after literal");
}
return s;
}
else
throw syntax_error ("Garbage after 'bp+' or 'bp-'");
}
else if (issep (*s))
{
aa.intval = 0;
return s;
}
else
{
throw syntax_error ("Invalid character after 'bp+' or 'bp-'");
}
}
else //single label
{
if (pass == 1)
{
long long n = lookup (tv.s);
if (n < 0)
{
throw syntax_error ("Unknown label");
}
else
aa.intval = n;
};
if (!issep (*s))
throw syntax_error ("Garbage after label");
return s;
};
}
if ((tt == TT_NONE) && (aa.am == AM_DIRECT))
aa.am = AM_NONE;
else
{
throw syntax_error ("Garbage after address mode modifier");
}
return s;
};
/*
* Analyze entire line of code
* Comments are already stripped from the line
*/
void
analyze (const char *s)
{
instruction instr;
instr.args[0].am = AM_NONE;
instr.args[1].am = AM_NONE;
instr.args[2].am = AM_NONE;
string label;
s = extract_label (s, label);
s = extract_instr (s, instr.oc, instr.at);
bool realmode;
if (instr.at == AT_REAL)
realmode = true;
else
realmode = false;
if (instr.oc != OC_NONE)
{
/* beware: inttoreal and realtoint are special cases
* with respect to the operand types - need to specify them explicitly */
s = extract_address (s, instr.args[0], realmode);
if (*s == ',')
{
if (instr.args[0].am == AM_NONE)
throw syntax_error ("Empty first operand");
s++;
s = extract_address (s, instr.args[1], realmode);
if (instr.args[1].am == AM_NONE)
throw syntax_error ("Empty second operand");
if (*s == ',')
{
s++;
if ((instr.oc != OC_JE) && (instr.oc != OC_JGE) && (instr.oc != OC_JG) && (instr.oc != OC_JLE) && (instr.oc != OC_JE)) //jumps are special - last arg always integer
s = extract_address (s, instr.args[2], realmode);
else
s = extract_address (s, instr.args[2], false);
if (instr.args[2].am == AM_NONE)
throw syntax_error ("Empty third operand");
}
else if (*s != '\0')
{
throw syntax_error ("Wrong separator");
}
}
else if (*s != '\0')
{
throw syntax_error ("Wrong separator");
}
}
else //OC_NONE
{
if (*s)
throw syntax_error ("Invalid opcode");
}
if (pass == 0)
if (label.length () != 0)
{
if (lookup (label) >= 0)
{
throw syntax_error (string ("Duplicate label ") + label);
}
symtab[label] = current_address;
};
if (instr.oc != OC_NONE)
{
if (instr.at == AT_NONE)
throw syntax_error ("No argument type specified");
if(instr.oc>=OC_FINAL)
throw syntax_error("Internal error: invalid opcode");
syntax_table[instr.oc](instr);
if (pass == 1)
instructions[current_address] = instr;
current_address++;
}
}