I am trying to build a 3 address code generator which would produce:
input:x=a+3*(b/7)
output: t1=b/7
t2=3*t1
t3=a+t2
x=t3
NO matter whatever i give as input the output is "syntax error".
I'm using Windows 10.
Yacc code:
%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define YYDEBUG 1
int yylex(void);
int t_count = 1;
void yyerror(char *s)
{
fprintf(stderr,"%s\n",s);
return;
}
char * generateToken(int i)
{
char* ch=(char*)malloc(sizeof(char)*5);
sprintf(ch,"t%d",i++);
return ch;
}
%}
%union { double dval; char ivar[50]; }
%token <ivar> NUMBER
%token <ivar> NAME
%type <ivar> expr
%type <ivar> term
%left '+' '-'
%left '*' '/'
%left '(' ')'
%right '='
%%
program:
line {
}
| program line {
}
;
line:
expr '\n' {
t_count =1;
}
| NAME '=' expr '\n' {
printf("%s = %s", $3,$1);
t_count=1;
}
;
expr:
expr '+' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s + %s",$$,$1,$3);
}
| expr '-' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s - %s",$$,$1,$3);
}
| expr '*' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s * %s",$$,$1,$3);
}
| expr '/' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s / %s",$$,$1,$3);
}
| term {
strcpy($$, $1);
}
| '(' expr ')' {
strcpy($$,generateToken(t_count));
printf("%s =( %s )" ,$$,$2);
}
;
term:
NAME {
strcpy($$, $1);
}
| NUMBER {
strcpy($$, $1);
}
;
%%
int main(void)
{
if (getenv("YYDEBUG")) yydebug = 1;
yyparse();
return 0;
}
Lex code:
%option noyywrap
%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "threeAdd.tab.h"
void yyerror(char*);
extern YYSTYPE yylval;
%}
NAME [a-zA-Z]
DIGIT [0-9]+
NUMBER [-]?{DIGIT}+(\.{DIGIT}+)?
%%
[ \t]+ { }
{NUMBER}
{
strcpy(yylval.ivar,yytext);
return *yylval.ivar;
}
"+" {
return *yytext;
}
"-" {
return *yytext;
}
"*" {
return *yytext;
}
"/" {
return *yytext;
}
"=" {
return *yytext;
}
"(" {
return *yytext;
}
")" {
return *yytext;
}
{NAME} {
strcpy(yylval.ivar,yytext);
return *yylval.ivar;
}
"\n" {
return *yytext;
}
exit {
return 0;
}
. {
char msg[25];
sprintf(msg," <%s>","invalid character",yytext);
yyerror(msg);
}
%%
Sample build & run:
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>flex file.l
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>bison -d file.y
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>gcc lex.yy.c file.tab.c -o ICG.exe
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>ICG.exe
3+9
syntax error
The basic problem is that you are use double-quote (" -- strings) for tokens in your yacc file (without defining any codes for them, so they're useless), and returning single character tokens in your lex file. As a result, none of the tokens will be recognized in your parser.
Replace all the " characters with ' characters on all the single character tokens in your yacc file (so "+" becomes '+' and "\n" becomes '\n').
Once you fix that, you have another problem: your lex rules for {DIGITS}+ and {NAME} don't return a token, so the token will be ignored (leading to syntax errors)
For debugging parser problems in general, it is often worth compiling with -DYYDEBUG and sticking yydebug = 1; into main before calling yyparse, which will cause the parser to print a trace of tokens seen and states visited. I often put
if (getenv("YYDEBUG")) yydebug = 1;
into main and just leave it there -- that way normally debugging won't be enabled, but if you set the environment variable YYDEBUG=1 before running your program, you'll see the debug trace (no need to recompile)
In order to return a token, your lexer rule needs to return the token. So your lexer rule for NUMBER should be:
{NUMBER} {
strcpy(yylval.ivar,yytext);
return NUMBER;
}
and similar for NAME. Note that the opening { of the code block must be on the same line as the pattern -- if it is on a separate line it will not be associated with the pattern.
Related
I'm using the Spirit error handling code from the article "Dispatching on Expectation Point Failures" at http://boost-spirit.com/home/2011/02/28/dispatching-on-expectation-point-failures/comment-page-1/, the last example there. My "diagnostics" and "error_handler_impl" classes are pretty much the same as is found in the article, but I can post them if someone thinks it is necessary.
In the code below, the start rule in question
comma = lit(',');
comma.name(",");
start = lit("begin") >> ident > comma >> ident;
has an expectation point after the "begin" keyword. In accordance with the article, I expected that a missing comma would cause error handler to be passed the qi::_4 value to be ",", which is the name of the comma rule. Instead, it is passing "sequence", causing the error handler to print a default message rather than the informative "Missing comma after begin keyword".
An idea what I am missing?
template <typename Iterator, typename Skipper = ascii::space_type>
class Grammar1 : boost::spirit::qi::grammar<Iterator, Skipper>
{
public:
typedef boost::spirit::qi::rule<Iterator, Skipper> rule_nil_T;
typedef boost::spirit::qi::rule<Iterator, string()> rule_str_T;
// structs from Rob Stewart's above-mentioned article
diagnostics<10> d1;
boost::phoenix::function<error_handler_impl> error_handler;
rule_str_T ident;
rule_nil_T comma;
rule_nil_T start;
Grammar1(void) : Grammar1::base_type(start)
{
ident %= lexeme [ qi::raw [ (qi::alpha | '_') >> *(qi::alnum | '_') ] ];
comma = lit(',');
comma.name(",");
start = lit("begin") >> ident > comma >> ident;
d1.add(",", "Missing comma after begin keyword");
on_error<fail>(start,
error_handler(ref(d1), _1, _2, _3, _4));
}
~Grammar1(void) { };
void parseInputFile(Iterator itr, Iterator itr_end)
{
bool r = phrase_parse(itr, itr_end, start, ascii::space);
if (r && itr == itr_end)
{
std::cout << "Parsing succeeded\n";
} else
{
string rest(itr, itr_end);
std::cout << "stopped at: \": " << rest << "\"\n";
}
}
};
I am currently trying to create a basic grammar that can take in and recognize shell commands. However, I am getting syntax errors that escape my understanding. I have drawn out a tree and, from what I can tell, I cover all the bases. Here is my lex file
%{
#include <cstring>
#include "y.tab.hh"
static void yyunput (int c,char *buf_ptr );
void myunputc(int c) {
unput(c);
}
%}
%option noyywrap
%%
return PIPE;
}
"<" {
return LESS;
}
"&" {
return AMP;
}
\n {
return NEWLINE;
}
[ \t] {
/* Discard spaces and tabs */
}
">" {
return GREAT;
}
"2>" {
return TGREAT;
}
">&" {
return GREATAMP;
}
">>" {
return DUBGREAT;
}
">>&" {
return DUBGREATAMP;
}
[^ \t\n][^ \t\n]* {
/* Assume that file names have only alpha chars */
yylval.cpp_string = new std::string(yytext);
return WORD;
}
And here is my yacc file
%code requires
{
#include <string>
#if __cplusplus > 199711L
#define register // Deprecated in C++11 so remove the keyword
#endif
}
%union
{
char *string_val;
// Example of using a c++ type in yacc
std::string *cpp_string;
}
%token <cpp_string> WORD
%token NOTOKEN GREAT NEWLINE PIPE LESS AMP TGREAT GREATAMP DUBGREAT DUBGREATAMP
%{
//#define yylex yylex
#include <cstdio>
#include "shell.hh"
void yyerror(const char * s);
int yylex();
%}
%%
goal:
command_list
;
command_list:
command_line
| command_list command_line
;
command_line:
pipe_list io_modifier_list background_optional NEWLINE
| NEWLINE
| error NEWLINE{yyerrok;}
;
pipe_list:
pipe_list PIPE command_and_args
| command_and_args
;
command_and_args:
command_word argument_list {
Shell::_currentCommand.
insertSimpleCommand( Command::_currentSimpleCommand );
}
;
argument_list:
argument_list argument
| /* can be empty */
;
io_modifier_list:
io_modifier_list iomodifier_opt
| /*empty*/
;
iomodifier_opt:
GREAT WORD {
printf(" Yacc: insert output \"%s\"\n", $2->c_str());
Shell::_currentCommand._outFile = $2;
}
| DUBGREAT WORD {
printf(" Yacc: insert output \"%s\"\n", $2->c_str());
Shell::_currentCommand._outFile = $2;
}
| DUBGREATAMP WORD {
printf(" Yacc: insert output \"%s\"\n", $2->c_str());
Shell::_currentCommand._outFile = $2;
Shell::_currentCommand._background = true;
}
| GREATAMP WORD {
printf(" Yacc: insert output \"%s\"\n", $2->c_str());
Shell::_currentCommand._outFile = $2;
Shell::_currentCommand._background = true;
}
| LESS WORD {
printf(" Yacc: insert input \"%s\"\n", $2->c_str());
Shell::_currentCommand._inFile = $2;
}
| /* can be empty */
;
background_optional:
AMP {
Shell::_currentCommand._background = true;
}
| /*empty*/
;
argument:
WORD {
printf(" Yacc: insert argument \"%s\"\n", $1->c_str());
Command::_currentSimpleCommand->insertArgument( $1 );
}
;
command_word:
WORD {
printf(" Yacc: insert command \"%s\"\n", $1->c_str());
Command::_currentSimpleCommand = new SimpleCommand();
Command::_currentSimpleCommand->insertArgument( $1 );
}
;
%%
void
yyerror(const char * s)
{
fprintf(stderr,"%s", s);
}
#if 0
main()
{
yyparse();
}
#endif
In the simplest use case, I tried ls -al. In my understanding, ls gets recognized as a command_word. Then -al gets recognized as an argument. This creates a new argument_list containing only -al. From there, command_and_args is created from the command_word ls and the argument_list -al. This creates a pipe_list that only contains this command_and_args. From there, a command_line is created with this new pipe_list, an empty io_modifier_list, an empty background_optional, and the newline character when I hit enter. This creates a command_list, which is the goal. However, my understanding is apparently incorrect because I am getting a syntax error and I was hoping someone could help me fix that lack of understanding.
Basically, I have an assignment where I need to make a compiler for C-, but we're doing it in 5 steps. One of the steps was to turn the BNF grammar to bison and then print a tree with what has been compiled. Let me explain:
BNF Grammar
1. program→declaration-list
2. declaration-list→declaration-list declaration | declaration
3. var-declaration| fun-declaration
4. var-declaration→type-specifierID;| type-specifierID[NUM];
5. type-specifier→int | void
6. fun-declaration→type-specifierID(params)compound-stmt
7. params→param-list| void
8. param-list→param-list,param | param
9. param→type-specifierID | type-specifierID[]
10. compound-stmt→{local-declarations statement-list}
11. local-declarations→local-declarations var-declaration| empty
12. statement-list→statement-list statement| empty
13. statement→expression-stmt| compound-stmt| selection-stmt | iteration-stmt | return-stmt
14. expession-stmt→expression;| ;
15. selection-stmt→if(expression)statement| if(expression) statement else statement
16. iteration-stmt→while(expression)statement
17. return-stmt→return; | return expression;
18. expression→var=expression| simple-expression
19. var→ID| ID[expression]
20. simple-expression→additive-expression relop additive-expression| additive-expression
21. relop→<=| <| >| >=| ==| !=
22. additive-expression→additive-expression addop term| term
23. addop→+| -
24. term→term mulop factor| factor
25. mulop→*| /
26. factor→(expression)| var| call| NUM
27. call→ID(args)
28. args→arg-list| empty
29. arg-list→arg-list,expression| expression
File: Project.fl
%option noyywrap
%{
/* Definitions and statements */
#include <stdio.h>
#include "project.tab.h"
int nlines = 1;
char filename[50];
%}
ID {letter}{letter}*
NUM {digit}{digit}*
letter [a-zA-Z]
digit [0-9]
%%
"if" { return T_IF; }
"else" { return T_ELSE; }
"int" { return T_INT; }
"return" { return T_RETURN; }
"void" { return T_VOID; }
"while" { return T_WHILE; }
"+" { return yytext[0]; }
"-" { return yytext[0]; }
"*" { return yytext[0]; }
"/" { return yytext[0]; }
">" { return T_GREAT; }
">=" { return T_GREATEQ; }
"<" { return T_SMALL; }
"<=" { return T_SMALLEQ; }
"==" { return T_COMPARE; }
"!=" { return T_NOTEQ; }
"=" { return yytext[0]; }
";" { return yytext[0]; }
"," { return yytext[0]; }
"(" { return yytext[0]; }
")" { return yytext[0]; }
"[" { return yytext[0]; }
"]" { return yytext[0]; }
"{" { return yytext[0]; }
"}" { return yytext[0]; }
(\/\*(ID)\*\/) { return T_COMM; }
{ID} { return T_ID; }
{NUM} { return T_NUM; }
\n { ++nlines; }
%%
File: project.y
%{
#include <stdio.h>
#include <stdlib.h>
extern int yylex();
extern int yyparse();
void yyerror(const char* s);
%}
%token T_IF T_ELSE T_INT T_RETURN T_VOID T_WHILE
T_GREAT T_GREATEQ T_SMALL T_SMALLEQ T_COMPARE T_NOTEQ
T_COMM T_ID T_NUM
%%
program: declaration-list { printf("program"); }
;
declaration-list: declaration-list declaration
| declaration
;
declaration: var-declaration
| fun-declaration
;
var-declaration: type-specifier T_ID ';'
| type-specifier T_ID'['T_NUM']' ';'
;
type-specifier: T_INT
| T_VOID
;
fun-declaration: type-specifier T_ID '('params')' compound-stmt
;
params: param-list
| T_VOID
;
param-list: param-list',' param
| param
;
param: type-specifier T_ID
| type-specifier T_ID'['']'
;
compound-stmt: '{' local-declarations statement-list '}'
;
local-declarations: local-declarations var-declaration
|
;
statement-list: statement-list statement
|
;
statement: expression-stmt
| compound-stmt
| selection-stmt
| iteration-stmt
| return-stmt
;
expression-stmt: expression ';'
| ';'
;
selection-stmt: T_IF '('expression')' statement
| T_IF '('expression')' statement T_ELSE statement
;
iteration-stmt: T_WHILE '('expression')' statement
;
return-stmt: T_RETURN ';'
| T_RETURN expression ';'
;
expression: var '=' expression
| simple-expression
;
var: T_ID { printf("\nterm\nfactor_var\nvar(x)"); }
| T_ID '['expression']'
;
simple-expression: additive-expression relop additive-expression
| additive-expression
;
relop: T_SMALLEQ
| T_SMALL
| T_GREAT
| T_GREATEQ
| T_COMPARE
| T_NOTEQ
;
additive-expression: additive-expression addop term
| term
;
addop: '+' { printf("\naddop(+)"); }
| '-' { printf("\naddop(-)"); }
;
term: term mulop factor
| factor
;
mulop: '*' { printf("\nmulop(*)"); }
| '/' { printf("\nmulop(/)"); }
;
factor: '('expression')' { printf("\nfactor1"); }
| var
| call
| T_NUM { printf("\nterm\nfactor(5)"); }
;
call: T_ID '('args')' { printf("\ncall(input)"); }
;
args: arg-list
| { printf("\nargs(empty)"); }
;
arg-list: arg-list',' expression
| expression
;
%%
int main(void) {
return yyparse();
}
void yyerror(const char* s) {
fprintf(stderr, "Parse error: %s\n", s);
exit(1);
}
And finally the tree that's asked to be replicated:
program
declaration_list
declaration
fun_definition(VOID-main)
params_VOID-compound
params(VOID)
compound_stmt
local_declarations
local_declarations
local_declarations(empty)
var_declaration(x)
type_specifier(INT)
var_declaration(y)
type_specifier(INT)
statement_list
statement_list
statement_list(empty)
statement
expression_stmt
expression
var(x)
expression
simple_expression
additive_expression
term
factor
call(input)
args(empty)
statement
expression_stmt
expression
var(y)
expression
simple_expression
additive_expression(ADDOP)
additive_expression
term
factor_var
var(x)
addop(+)
term
factor(5)
Sample code in which the tree is based off
/* A program */
void main(void)
{
int x; int y;
x = input();
y = x + 5;
}
I've turned the BNF grammar to the actual .y file, but I'm having problems printing out where exactly the messages should go. Usually, a grammar would finish THEN print.
The desired output you present is the result of a pre-order walk of the parse tree.
However, bison generates a bottom-up parser, which performs semantic actions for a node in the parse tree when the node's subtree is complete. Printing the node in the semantic action therefore produces a post-order walk. I suppose that is what you mean by your last sentence.
While there are a variety of possible solutions, the simplest one is probably to construct a parse tree during the parse and then print it out at the end of the parse. (You could print the tree in the semantic action for the start production, but that will sometimes result in a parse tree being printed for an erroneous input. Better is to return the root of the parse tree and print it from the main program after verifying that the parse was successful.)
I don't know where "construct a parse tree" fits in the expected progression of your project. Parse trees are of little use in most applications. Much more common is the construction of an abstract syntax tree (AST) which omits many of the irrelevant details from the parse (such as unit productions). You can construct an AST from a parse tree, but it is generally simpler to construct it directly in the parse actions: the code looks very similar but there is less of it precisely because tree nodes don't have to be built for unit productions.
I have a program that is supposed to take in a paragraph like
Testing#the hash#tag
#program!#when #beginning? a line
or #also a #comma,
and output something like
#the
#tag
#program
#when
#beginning
#also
#comma,
I feel like the logic makes sense, but obviously not because the program never seems to get into the line of input. The problem is almost definitely in the last source file below.
Here is the main source program
#include "HashTagger.h"
#include <string>
#include <iostream>
using namespace hw02;
using namespace std;
int main() {
// Construct an object for extracting the
// hashtags.
HashTagger hashTagger;
// Read the standard input and extract the
// hashtags.
while (true) {
// Read one line from the standard input.
string line;
getline(cin, line);
if (!cin) {
break;
}
// Get all of the hashtags on the line.
hashTagger.getTags(line);
}
// Print the hashtags.
hashTagger.printTags();
// Return the status.
return 0;
}
my header file
#ifndef HASHTAGGER_H
#define HASHTAGGER_H
#include <string>
namespace hw02 {
class HashTagger {
public:
void getTags(std::string line);
void printTags();
private:
std::string hashtags_;
};
}
#endif
and a source file
the test in the source file seems to show that the program only gets to the second line and then stops before grabbing the last 2 hashtags
#include "HashTagger.h"
#include <iostream>
using namespace std;
using namespace hw02;
void HashTagger::getTags(string line) {
// Loop over all characters in a line that can begin a hashtag
int b = 0;
string hashtags_ = "";
for (unsigned int j = 0; j < line.length(); ++j) {
char c = line.at(j);
// if "#" is found assign beginning of capture to b
if (c == '#') {
b = j;
// if the beginning is less than the end space, newline, ".", "?", or "!" found, add substring of the hashtag to hashtags_
}
if (b < j && (c == ' ' || c == '\n' || c == '.' || c == '?' || c == '!' )) {
hashtags_ = hashtags_ + "\n" + line.substr(b, j - b + 1);
b = 0;
//Test// cout << b << "/" << j << "/" << c << "/" << hashtags_ << "/" << endl;
}
}
}
void HashTagger::printTags() {
// print out hashtags_ to the console
cout << hashtags_ << endl;
}
You are redeclaring hashtags_ inside your getTags function. Therefore, all string modifications operate on a local variable instead of the class member variable.
Change the line
string hashtags_ = "";
to
hashtags_ = "";
in order to avoid the redeclaration and operate on the class member variable used for the output later on.
Also, make sure that your input is terminated with two newline characters (\n\n), to avoid breaking out of the main loop too early, or move your check and break statement after the getTags call:
while (true) {
// Read one line from the standard input.
string line;
getline(cin, line);
// Get all of the hashtags on the line.
hashTagger.getTags(line);
if (!cin) {
break;
}
}
I am new with unix and I've got an assignemnt on college to build a simple shell in c with built in cd and kill command..
This is my code which is not working..tbh I dont understand it the best so Im not suprised it is not working.. can you help me with it? Also have no idea how I would implement kill command. thank you!
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024
const int ARGSIZE = 20;
void execute(char*args[])
{
int pid, status;
pid = fork();
if(pid<0)
{
perror("Error forking!");
}
else if(pid > 0)
{
while(wait(&status) != pid)
continue;
}
else if(pid == 0)
{
if (execvp(args[0], args) == -1)
{
perror("Error");
}
}
}
void cd(char*directory)
{
int ret = 0;
if(directory == '\0')
directory = getenv("HOME");
ret = chdir(directory);
if(ret != 0)
fprintf(stderr,"Failed to enter directory: %s\n",directory);
else
printf("%s\n",directory);
}
int main()
{
char line[BUF_SIZE];
char *args[ARGSIZE];
int argIndex = 0;
while(1){
printf("> ");
fgets(line, BUF_SIZE, stdin);
char *token;
token = strtok(line," ");
while(token!=NULL)
{
args[argIndex]=token;
token = strtok(NULL," ");
argIndex++;
}
args[argIndex]=NULL;
if(strcmp(args[0], "quit") == 0 || strcmp(args[0], "exit") == 0)
break;
if(line== "\n")
printf("> ");
else if ((strcmp(args[0], "cd") == 0))
cd(args[1]);
else
execute(args);
}
return 0;
}
You were on the right track. There were a few subtle issues where you were not accounting for the trailing '\n' that would remain in line as the last character following whatever was entered at the prompt. Including " \n" in the delimiters used to tokenize the input with strtok will remove it, allowing valid strcmp comparisons with the final token (e.g. that is why quit and exit would not quit the application).
Other than than, there were several additional things you could do a little different/better, you could handle directories entered as e.g. '~/somedir', and similar additional checks that could be employed. I have notated most below as comments to the code.
Look over the changes below and let me know if you have any questions. There are always additional checks that can be added, etc.., but on balance your approach to the problem was pretty good. (note: some of the changes made were non-substantive, e.g. "shell> " as the prompt, instead of "> ". Just handle any of those as you wish.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
enum {ARGSIZE = 20, BUF_SIZE = 1024};
void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);
int main (void)
{
char line[BUF_SIZE] = {0};
char *args[ARGSIZE] = {NULL};
char *token;
int i, argIndex = 0;
while (1) {
argIndex = 0; /* reinitialize variables */
for (i = 0; i < ARGSIZE; i++)
args[i] = NULL;
printf ("shell> "); /* prompt */
if (fgets (line, BUF_SIZE, stdin) == NULL) {
printf ("EOF received\n");
return 0;
}
if (*line == '\n') /* Enter alone */
continue;
token = strtok (line, " \n"); /* add \n to delimiters */
while (token != NULL) {
args[argIndex] = token;
token = strtok (NULL, " \n");
argIndex++;
}
if (!argIndex) continue; /* validate at least 1 arg */
if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
break;
/* handle 'cd' or 'kill' separately */
if ((strcmp (args[0], "cd") == 0))
cd (args[1]);
else if ((strcmp (args[0], "kill") == 0)) {
if (args[1]) killpid (args[1], SIGTERM);
}
else
execute (args);
}
return 0;
}
void execute (char **args)
{
int pid, status;
pid = fork ();
if (pid < 0) {
perror ("Error forking!");
return;
}
else if (pid > 0) {
while (wait (&status) != pid)
continue;
}
else if (pid == 0) {
if (execvp (args[0], args) == -1) {
perror ("Error");
}
_exit (EXIT_FAILURE);
}
}
void cd (char *directory)
{
char dir[BUF_SIZE] = {0};
if (!directory) { /* handle 'cd' */
directory = getenv ("HOME");
if (chdir (directory))
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
return;
}
if (*directory == '~') { /* handle cd ~/stuff */
strcpy (dir, getenv ("HOME"));
strcat (dir, "/");
strcat (dir, directory + 2);
if (chdir (dir))
fprintf (stderr, "Failed to enter directory: %s\n", dir);
else
printf ("%s\n", dir);
return;
}
if (chdir (directory)) /* handle given directory */
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
}
int killpid (char *pidstr, int sig)
{
pid_t pid = (pid_t)atoi (pidstr);
if (pid < 1) {
fprintf (stderr, "warning: requested pid < 1, ignoring\n");
return (int)pid;
}
printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
// return kill (pid, sig);
return 0;
}
Sample Usage/Output
$ ./bin/ushell
shell> cd
/home/david
shell> cd ~/tmp
/home/david/tmp
shell> kill 18004
killing pid '18004' with signal '15'
shell>
shell> quit