So for a project that I'm working on, I am using Lex and Yacc to parse a FTP configuration file. The configuration files look something like this:
global {
num_daemons = 10
etc = /etc/ftpd
};
host "ftp-1.foobar.com" {
ftproot = /var/ftp/server1
max_out_bandwidth = 20.7
};
host "ftp-2.foobar.com" {
ftproot = /var/ftp/server2
exclude = /var/ftp/server2/private
};
host "ftp-3.foobar.com" {
ftproot = /var/ftp/server3
};
Now, my question is, how do I obtain this information in a usable way? Let's say I wanted to put things like the address after the host token into a struct. How would I do that? Also, how would I simply print out the values that I've parsed to the command line? Also, to run it, do I just cat the config file and pipe in the compiled c program? Thanks in advance for any help!
Here is my code:
%{
// tokens.l
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"
int yyparse();
%}
%option noyywrap
%x OPTION
%x OPTID
%%
<INITIAL>global { return GLOBAL; }
<INITIAL>host { return HOST; }
<INITIAL>"[a-zA-z1-9./-]+" { return NAME; }
<INITIAL>\{ { return CURLY_OPEN; BEGIN OPTION; }
<INITIAL>\n { return EOLN; }
<INITIAL><<EOF>> { return EOFTOK; }
<OPTION>[a-zA-z1-9./-_]+ { return ID_NAME; BEGIN OPTID; }
<OPTION>[\t] {}
<OPTION>[\};] { return OPTION_CLOSE; BEGIN INITIAL;}
<OPTID>[a-zA-z1-9./-]+ { return ID_STRING; BEGIN OPTION; }
<OPTID>[0-9.]+ { return ID_NUM; BEGIN OPTION; }
<OPTID>[\n] { return EOLN; }
%%
int main(int argc, char **argv) {
// Where I am confused..
}
and my yacc file:
%{
// parse.y
#include <stdio.h>
#include <stdlib.h>
int yyerror(char *);
int yylex(void);
%}
%token ERROR EOLN EOFTOK
%token OPTION_CLOSE GLOBAL HOST NAME ID_NAME ID_STRING ID_NUM CURLY_OPEN
%%
input
: lines EOFTOK { YYACCEPT; }
;
lines
:
| lines line
;
line
: option
| opident
| OPTION_CLOSE
;
option
: GLOBAL CURLY_OPEN
| HOST NAME CURLY_OPEN
;
opident
: ID_NAME '=' ID_STRING
| ID_NAME '=' ID_NUM
;
%%
int yyerror(char *msg) {}
You would generally have variables which were accessible and set up before calling the parser, like a linked list of key/value pairs:
typedef struct sNode {
char *key;
char *val;
struct sNode *next;
} tNode;
tNode *lookupHead = NULL;
Then, in your Yacc code, something like:
opident
: ID_NAME '=' ID_STRING { addLookupStr (lookupHead, $1, $3); }
| ID_NAME '=' ID_NUM { other function call here }
;
This would basically execute that code as the rules are found (replacing the $ variables with the item in the rule, $1 is the value for the ID_NAME token, $2 is the =, and so on).
The function would be something like:
void addLookupStr (char *newkey, char *newval) {
// Check for duplicate keys, then attempt to add. All premature returns
// should also be logging errors and setting error flags as needed.
tNode *curr = lookupHead;
while (curr != NULL) {
if (strcmp (curr->key, newkey) == 0)
return;
curr = curr->next;
}
if ((curr = malloc (sizeof (tNode))) == NULL)
return;
if ((curr->key = strdup (newkey)) == NULL) {
free (curr);
return;
}
if ((curr->val = strdup (newval)) == NULL) {
free (curr->newkey);
free (curr);
return;
}
// All possibly-failing ops complete, insert at head of list.
curr->next = lookupHead;
lookupHead = curr;
}
Related
In this code,
How many times would the generated string be copied for each case(case 1, case 2)?
Could anyone confirm my answers in the code body?
If so, can I tell case 2 is more efficient than case 1?
Or any other suggestions?
#include <optional>
#include <string>
std::optional<std::string> GenerateString() {
std::string s = "very long string";
return s;
}
class Message {
public:
Message(const std::string &s) : payload_{s} {}
Message(std::string &&s) : payload_{std::move(s)} {}
private:
std::string payload_;
};
int main() {
// case 1
const std::optional<std::string> &opt1 = GenerateString(); // no copy
const std::string &s1 = *opt1; // no copy
Message msg1{s1}; // copy: s1 -> payload_
// case 2
std::optional<std::string> &&opt2 = GenerateString(); // no copy
std::string &&s2 = std::move(*opt2); // no copy
Message msg2{std::move(s2)}; // no copy
return 0;
}
I tried solving this question and the answer comes out to be option c. But in few textbooks answer given is option b. I am confused what would be the correct answer? Plz help me out!
GAAAAT is the correct answer; it is the output produced by a parser which honours the order of the actions in the translation rules (some of which occur in mid-rule).
Yacc/bison is one such parser, which makes it very easy to verify:
%{
#include <ctype.h>
#include <stdio.h>
void yyerror(const char* msg) {
fprintf(stderr, "%s\n", msg);
}
int yylex(void) {
int ch;
while ((ch = getchar()) != EOF) {
if (isalnum(ch)) return ch;
}
return 0;
}
%}
%%
S: 'p' { putchar('G'); } P
P: 'q' { putchar('A'); } Q
P: 'r' { putchar('T'); }
P: %empty { putchar('E'); }
Q: 's' { putchar('A'); } P
Q: %empty { putchar('O'); }
%%
int main(void) {
yyparse();
putchar('\n');
}
$ bison -o gate.c gate.y
$ gcc -std=c99 -Wall -o gate gate.c
$ ./gate<<<pqsqsr
GAAAAT
If we modify the grammar to put all of the actions at the end of their respective rule, we obtain answer (b). (Other than the grammar, everything is the same as the previous example, so I'm only showing the new translation rules.)
S: 'p' P { putchar('G'); }
P: 'q' Q { putchar('A'); }
P: 'r' { putchar('T'); }
P: %empty { putchar('E'); }
Q: 's' P { putchar('A'); }
Q: %empty { putchar('O'); }
$ bison -o gate_no_mra.c gate_no_mra.y
$ gcc -std=c99 -Wall -o gate_no_mra gate_no_mra.c
$ ./gate_no_mra<<<pqsqsr
TAAAAG
I try to do this tutorial in rust, so far I have a lot of problems interfacing the C library into Rust.
C equivalent code:
#include <stdio.h>
#include <stdlib.h>
#include <editline/readline.h>
#include <editline/history.h>
int main(int argc, char** argv) {
/* Print Version and Exit Information */
puts("Lispy Version 0.0.0.0.1");
puts("Press Ctrl+c to Exit\n");
/* In a never ending loop */
while (1) {
/* Output our prompt and get input */
char* input = readline("lispy> ");
/* Add input to history */
add_history(input);
/* Echo input back to user */
printf("No you're a %s\n", input);
/* Free retrived input */
free(input);
}
return 0;
}
So far i got this:
extern crate libc;
use std::c_str;
#[link(name = "readline")]
extern {
fn readline (p: *const libc::c_char) -> *const libc::c_char;
}
fn rust_readline (prompt: &str) -> Option<Box<str>> {
let cprmt = prompt.to_c_str();
cprmt.with_ref(|c_buf| {
unsafe {
let ret = c_str::CString::new (readline (c_buf), true);
ret.as_str().map(|ret| ret.to_owned())
}
})
}
fn main() {
println!("Lispy Version 0.0.1");
println!("Press Ctrl+c to Exit.\n");
// I want to have "history" in Linux of this:
//
// loop {
// print!("lispy> ");
// let input = io::stdin().read_line().unwrap();
// print!("No you're a {}", input);
// }
loop {
let val = rust_readline ("lispy> ");
match val {
None => { break }
_ => {
let input = val.unwrap();
println!("No you're a {}", input);
}
}
}
}
Especifically, I'm having issues with rust_readline function, i don't understand very well what's doing inside.
Edit Cargo.toml, put this:
[dependencies.readline]
git = "https://github.com/shaleh/rust-readline"
Code corrected:
extern crate readline;
fn main() {
println!("Lispy Version 0.0.1");
println!("Press Ctrl+c to Exit.\n");
loop {
let input = readline::readline("lispy> ").unwrap();
readline::add_history(input.as_str());
println!("No you're a {}", input);
}
}
Happy Lisping :-) .
Funny thing is, that I found this question reading the very same book, but not including any book specific information in my search query.
There is now a crate for this. Facon's solution worked for me, but the prompt string always printed as garbage using that library, so I looked for another crate and found one working nicely. Here is an updated example:
cargo.toml:
[dependencies]
# https://crates.io/crates/rustyline
rustyline = "3.0.0"
main.rs:
extern crate rustyline;
use rustyline::error::ReadlineError;
use rustyline::Editor;
const HISTORY_FILENAME: &str = "history.txt";
fn main() {
println!("Lispy Version 0.0.1");
println!("Press Ctrl+c to Exit.\n");
// We create an editor for the readline history.
let mut readline_editor = Editor::<()>::new();
// And then load the history, if it exists.
if readline_editor.load_history(HISTORY_FILENAME).is_err() {
println!("No previous history.");
}
loop {
// We read some input from CLI.
let readline = readline_editor.readline("LISPY>> ");
// The reading of the input could fail, if a user uses special
// key combinations. So we match against the readline Result
// type. Result can either be some `Ok` or an some `Err`.
match readline {
Ok(line) => {
readline_editor.add_history_entry(line.as_ref());
println!("No, you are {}", line);
},
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break
},
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break
},
Err(err) => {
println!("Error: {:?}", err);
break
}
}
readline_editor.save_history(HISTORY_FILENAME).expect("Could not save to readline history.");
}
}
its been a week im trying to figure out how to finish this assignment. Its kind of not clear how to connect my if statements with stacks.
here is my codes, its made of 3 files
the assignment problem is, brackets and parenthesis should match, which means if we have left bracket, after that should be right one, otherwise it will say not valid.
i'll be very happy any hint or fixes.
cstack.h file
#include <iostream>
class FullStack{};
class EmptyStack{};
class cstack
{
private:
int top; // Index to top of the stack
char data[21]; // The stack
public:
cstack(); // Class constructor
void Push(char); // Push an item onto the stack
void Pop(); // Pop an item from the stack
bool Top();
bool IsEmpty(); // Return true if stack is empty
bool IsFull(); // Return true if stack is full
};
cstack.cpp file
#include <iostream>
#include "cstack.h"
#include <stack>
#include <cstring>
using namespace std;
cstack::cstack()
{
top = -1;
}
bool cstack::IsEmpty()
{
return (top == -1);
}
bool cstack::IsFull()
{
return (top == 21);
}
void cstack::Push(char newItem)
{
if (IsFull())
{
throw FullStack();
}
top++;
data[top] = newItem;
}
void cstack::Pop()
{
if(IsEmpty())
{
throw EmptyStack();
}
top--;
}
bool cstack::Top()
{
if (IsEmpty())
{
throw EmptyStack();
}
return data[top];
}
test.cpp file
#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;
#include "cstack.h"
bool isValidExpression (cstack&, char*);
int main (void)
{
char expression[21];
cstack stack1;
cout<< "Enter an expression: ";
cin >>expression;
if (isValidExpression (stack1, expression))
{
cout << "\nIt's a valid expression\n\n";
}
else
{
cout << "\nIt's NOT a valid expression\n\n";
}
system("pause");
return 0;
}
bool isValidExpression (cstack& stackA, char* strExp)
{
for(int i = 0; i < 21 ; i++)
{
if( strExp[stackA.Top()] == '[' || strExp[stackA.Top()] == '{' || strExp[stackA.Top()] == '(')
{
stackA.Push( strExp[i] );
}
if( strExp[stackA.Top()] == ']' || strExp[stackA.Top()] == '}' || strExp[stackA.Top()] == ')')
{
if(strExp[i] == '[' && strExp[stackA.Top()] == ']')
{
return true;
}else
{
return false;
}
}
}
return true;
}
For this problem you normaly do this:
take each char from the input
push every opening bracket on the stack
if you get a closing bracket check top element of your stack.
if that element is the right opening bracket remove it from stack.
if that element is not the right opening bracket return false.
As Nikhil mentioned in the comment, normaly pop() should return the popped element, but in following code I used your stack.
for(int i = 0; i < 21 ; i++)
{
if(strExp[i] == '[' || strExp[i] == '{' || strExp[i] == '(')
{
stackA.Push( strExp[i] );
}
if( strExp[i] == ']')
{
if(!stackA.IsEmpty && stackA.Top() == '[')
{
stackA.Pop();
} else {
return false;
}
}
if( strExp[i] == '}')
{
if(!stackA.IsEmpty && stackA.Top() == '{')
{
stackA.Pop();
} else {
return false;
}
}
if( strExp[i] == ')')
{
if(!stackA.IsEmpty && stackA.Top() == '(')
{
stackA.Pop();
} else {
return false;
}
}
}
return true;
edit:
when using ´pop()´ whenever we find a matching closing bracket we make sure, that on top of the stack there is always the last opened bracket. You can close that bracket or open another one, but you can't close earlier brackets.
The error you described occurs when you find a closing bracket and have an empty stack. So you have to check that first. if(!stackA.IsEmpty && stackA.Top == '['). See my edited code. Normaly with this code "[]" should be valid, i'll doublecheck and tell you, if i find another mistake.
I'm trying to present to the screen an error output when the user enters an incomplete
define , e.g :
#define A // this is wrong , error message should appear
#define A 5 // this is the correct form , no error message would be presented
but it doesn't work , here's the code :
%{
#include <stdio.h>
#include <string.h>
%}
%s FULLCOMMENT
%s LINECOMMENT
%s DEFINE
%s INCLUDE
%s PRINT
%s PSEUDO_C_CODE
STRING [^ \n]*
%%
<FULLCOMMENT>"*/" { BEGIN INITIAL; }
<FULLCOMMENT>. { /* Do Nothing */ }
<INCLUDE>"<stdio.h>"|"<stdlib.h>"|"<string.h>" { BEGIN INITIAL; }
<INCLUDE>. { printf("error\n"); return 0 ; }
<DEFINE>[ \t] { printf("eat a space within define\n"); }
<DEFINE>{STRING} { printf("eat string %s\n" , yytext);}
<DEFINE>\n { printf("eat a break line within define\n"); BEGIN INITIAL; }
"#include" { BEGIN INCLUDE; }
"#define" { printf("you gonna to define\n"); BEGIN DEFINE; }
"#define"+. { printf("error\n"); }
%%
int yywrap(void) { return 1; } // Callback at end of file
int main(void) {
yylex();
return 0 ;
}
Where did I go wrong ?
Here is the output :
a#ubuntu:~/Desktop$ ./a.out
#define A 4
error
A 4
#define A
error
A
The rule "#define"+. is longer and gets precedence over the earlier #define even for correct input. You could say just this :-
"#define"[:space:]*$ {printf("error\n"); }
Consider using the -dvT options with flex to get detailed debug output. Also I am not sure if you need such extensive use of states for anything except maybe comments. But you would know better.