Inital commit. Solutions to k&r chapter one
commit
9890fece0f
|
@ -0,0 +1,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
main()
|
||||
{
|
||||
printf("hello world\n");
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#include <stdio.h>
|
||||
|
||||
main()
|
||||
{
|
||||
float fahr, celsius;
|
||||
int lower, upper, step;
|
||||
|
||||
lower = 0;
|
||||
upper = 300;
|
||||
step = 20;
|
||||
|
||||
printf("Fahr\tCels\n");
|
||||
|
||||
fahr = lower;
|
||||
while (fahr <= upper) {
|
||||
celsius = (5.0 / 9.0) * (fahr - 32.0);
|
||||
printf("%4.0f\t%3.1f\n", fahr, celsius);
|
||||
fahr = fahr + step;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#include <stdio.h>
|
||||
|
||||
main()
|
||||
{
|
||||
int fahr, celsius;
|
||||
int lower, upper, step;
|
||||
|
||||
lower = 0;
|
||||
upper = 300;
|
||||
step = 20;
|
||||
|
||||
printf("Cels\tFahr\n");
|
||||
|
||||
celsius = lower;
|
||||
while (celsius <= upper) {
|
||||
fahr = (celsius / 5) * 9 + 32;
|
||||
printf("%4d\t%4d\n", celsius, fahr);
|
||||
celsius = celsius + step;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define LOWER 0
|
||||
#define UPPER 300
|
||||
#define STEP 20
|
||||
|
||||
main()
|
||||
{
|
||||
int fahr;
|
||||
|
||||
for (fahr = UPPER; fahr >= LOWER; fahr = fahr - STEP)
|
||||
printf("%3d %6.1f\n", fahr, (5.0 / 9.0) * (fahr - 32));
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void main()
|
||||
{
|
||||
printf("%d\n", getchar() != EOF);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void main()
|
||||
{
|
||||
printf("%d\n", EOF);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void main()
|
||||
{
|
||||
int c;
|
||||
long bl, tb, nl;
|
||||
|
||||
bl = tb = nl = 0;
|
||||
|
||||
while ((c = getchar()) != EOF)
|
||||
{
|
||||
if (c == ' ')
|
||||
++bl;
|
||||
if (c == '\t')
|
||||
++tb;
|
||||
if (c == '\n')
|
||||
++nl;
|
||||
}
|
||||
printf("blanks : %ld\ntabs : %ld\nnewlines : %ld\n", bl, tb, nl);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define BLANK ' '
|
||||
|
||||
void main()
|
||||
{
|
||||
int c, prev = -1;
|
||||
|
||||
while ((c = getchar()) != EOF) {
|
||||
if (prev != BLANK || c != BLANK)
|
||||
putchar(c);
|
||||
prev = c;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void main()
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = getchar()) != EOF) {
|
||||
if (c == '\t')
|
||||
printf("\\t");
|
||||
else if (c == '\b')
|
||||
printf("\\b");
|
||||
else if (c == '\\')
|
||||
printf("\\\\");
|
||||
else
|
||||
putchar(c);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define IN 0
|
||||
#define OUT 1
|
||||
|
||||
void main()
|
||||
{
|
||||
int c, state = OUT;
|
||||
|
||||
while ((c = getchar()) != EOF) {
|
||||
if (c == ' ' || c == '\n' || c =='\t') {
|
||||
if (state == IN) {
|
||||
putchar('\n');
|
||||
state = OUT;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
putchar(c);
|
||||
state = IN;
|
||||
}
|
||||
if (state == IN)
|
||||
putchar('\n');
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define MAXLEN 10
|
||||
|
||||
/* print historgram of word lengths */
|
||||
void main()
|
||||
{
|
||||
int c, i, len;
|
||||
/* no word has len = 0; we subscribe with count-1 */
|
||||
/* the last element is the count of words wiht len > MAXLEN */
|
||||
int counts[MAXLEN + 1];
|
||||
|
||||
/* initializing */
|
||||
len = 0;
|
||||
for (i = 0; i <= MAXLEN; ++i)
|
||||
counts[i] = 0;
|
||||
|
||||
/* counting */
|
||||
while ((c = getchar()) != EOF) {
|
||||
if (c == ' ' || c == '\n' || c == '\t') {
|
||||
if (len > 0) {
|
||||
if (len > MAXLEN)
|
||||
++counts[MAXLEN];
|
||||
else
|
||||
++counts[len-1];
|
||||
len = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
++len;
|
||||
}
|
||||
|
||||
int j, max, bound;
|
||||
|
||||
bound = max = 0;
|
||||
|
||||
for (i = 0; i <= MAXLEN; ++i)
|
||||
if (counts[i] > 0) {
|
||||
bound = i;
|
||||
if (counts[i] > max)
|
||||
max = counts[i];
|
||||
}
|
||||
|
||||
/* printing horizontal */
|
||||
printf("----- horizontal -----\n");
|
||||
for (i = 0; i <= bound; ++i) {
|
||||
if (i == MAXLEN)
|
||||
printf(">%2d ", MAXLEN);
|
||||
else
|
||||
printf("%3d ", i + 1);
|
||||
for (j = 0; j < counts[i]; ++j)
|
||||
putchar('#');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
/* printing vertical */
|
||||
printf("----- vertical -----\n");
|
||||
for (i = max; i > 0; --i) {
|
||||
for (j = 0; j <= bound; ++j)
|
||||
if (counts[j] >= i)
|
||||
putchar('#');
|
||||
else
|
||||
putchar(' ');
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define CHARS 254
|
||||
|
||||
/* prints character frequency histogram */
|
||||
void main()
|
||||
{
|
||||
int i, c;
|
||||
int counts[CHARS];
|
||||
|
||||
/* initializing */
|
||||
for (i = 0; i < CHARS; ++i)
|
||||
counts[i] = 0;
|
||||
|
||||
/* counting */
|
||||
while ((c = getchar()) != EOF) {
|
||||
++counts[c];
|
||||
}
|
||||
|
||||
/* printing */
|
||||
for (c = 0; c < CHARS; ++c) {
|
||||
if (counts[c] == 0)
|
||||
continue;
|
||||
|
||||
if (c == '\n')
|
||||
printf("\\n ");
|
||||
else if (c == ' ')
|
||||
printf("' ' ");
|
||||
else if (c == '\t')
|
||||
printf("\\t ");
|
||||
else if (c == '\b')
|
||||
printf("\\b ");
|
||||
else
|
||||
printf("%c ", c);
|
||||
|
||||
for (i = 0; i < counts[c]; ++i)
|
||||
putchar('#');
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define LOWER 0
|
||||
#define UPPER 300
|
||||
#define STEP 20
|
||||
|
||||
float cels_of_fahr(float fahr);
|
||||
|
||||
int main()
|
||||
{
|
||||
int fahr;
|
||||
|
||||
printf("%3c %6c\n", 'F', 'C');
|
||||
for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP)
|
||||
printf("%3d %6.1f\n", fahr, cels_of_fahr(fahr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
float cels_of_fahr(float fahr)
|
||||
{
|
||||
return (5.0/9.0) * (fahr-32);
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
#include <stdio.h>
|
||||
#define MAXLINE 1000
|
||||
|
||||
int mygetline(char line[], int maxline);
|
||||
void copy(char to[], char from[]);
|
||||
|
||||
/* print longest input line */
|
||||
int main()
|
||||
{
|
||||
int len, max; /* current, max lenght */
|
||||
char line[MAXLINE+1], longest[MAXLINE+1]; /* current, longest line; +1 for \0 */
|
||||
|
||||
max = 0;
|
||||
while ((len = mygetline(line, MAXLINE)) > 0)
|
||||
if (len > max) {
|
||||
max = len;
|
||||
copy(longest, line);
|
||||
}
|
||||
|
||||
if (max > 0) {
|
||||
printf("%d ", max);
|
||||
if (max <= MAXLINE && longest[max-1] == '\n') {
|
||||
longest[max-1] = '\\';
|
||||
printf("\n%sn\n", longest);
|
||||
} else if (max <= MAXLINE) {
|
||||
printf("\n%s\n", longest);
|
||||
} else
|
||||
printf("(first %d chars)\n%s...\n", MAXLINE, longest);
|
||||
} else
|
||||
printf("No lines found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* mygetline : read part of line smaller than lim-1 into s, return length */
|
||||
int mygetline(char s[], int maxline)
|
||||
{
|
||||
int c, i;
|
||||
|
||||
for (i=0; (c=getchar()) != EOF; ++i) {
|
||||
if (i < maxline)
|
||||
s[i] = c;
|
||||
if (c == '\n') {
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < maxline)
|
||||
s[i] = '\0';
|
||||
else
|
||||
s[maxline] = '\0';
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* copy : copy 'from' to 'to'; assume 'to' is big enough */
|
||||
void copy(char to[], char from[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; (to[i] = from[i]) != '\0'; ++i)
|
||||
;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* print line number and lines longer than 80 chars (excluding \n) */
|
||||
int main()
|
||||
{
|
||||
int c, i, ln;
|
||||
char buff[81]; /* +1 for \0 */
|
||||
|
||||
ln = 1;
|
||||
buff[80] = '\0';
|
||||
|
||||
for (i = 0; (c = getchar()) != EOF; ++i) {
|
||||
if (c == '\n') {
|
||||
if (i > 80)
|
||||
putchar('\n');
|
||||
++ln;
|
||||
i = -1;
|
||||
} else if (i < 80) {
|
||||
buff[i] = c;
|
||||
} else {
|
||||
if (i == 80)
|
||||
printf("%d %s", ln, buff);
|
||||
putchar(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 80 && c != '\n')
|
||||
putchar('\n');
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#include <stdio.h>
|
||||
#define MAXBUFF 1000
|
||||
|
||||
/* removes trailing spaces and tabs */
|
||||
int main()
|
||||
{
|
||||
int i, c;
|
||||
char buff[MAXBUFF+1]; /* +1 fo \0 */
|
||||
|
||||
i = 0;
|
||||
buff[MAXBUFF] = '\0';
|
||||
|
||||
while ((c = getchar()) != EOF) {
|
||||
if (c == ' ' || c == '\t') {
|
||||
if (i < MAXBUFF) {
|
||||
buff[i] = c;
|
||||
++i;
|
||||
} else {
|
||||
/* gracefully handle overflow */
|
||||
printf("%s", buff);
|
||||
i = 0;
|
||||
}
|
||||
} else if (c == '\n') {
|
||||
buff[0] = c;
|
||||
i = 1;
|
||||
} else {
|
||||
if (i > 0) {
|
||||
buff[i] = '\0';
|
||||
printf("%s", buff);
|
||||
i = 0;
|
||||
}
|
||||
putchar(c);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#include <stdio.h>
|
||||
#define MAXLINE 1000
|
||||
|
||||
void reverse(char s[]);
|
||||
int mystrlen(char s[]);
|
||||
int get_line(char s[], int maxline);
|
||||
|
||||
/* reverses input line by line */
|
||||
int main()
|
||||
{
|
||||
int end = 0;
|
||||
char line[MAXLINE + 1];
|
||||
|
||||
while (end != EOF) {
|
||||
end = get_line(line, MAXLINE);
|
||||
reverse(line);
|
||||
printf("%s", line);
|
||||
if (end != EOF)
|
||||
putchar(end);
|
||||
}
|
||||
}
|
||||
|
||||
/* reverses string 's' in place */
|
||||
void reverse(char s[])
|
||||
{
|
||||
char c;
|
||||
int i, len = mystrlen(s);
|
||||
|
||||
for (i = 0; i < len / 2; ++i) {
|
||||
c = s[i];
|
||||
s[i] = s[len-i-1];
|
||||
s[len-i-1] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/* returns length of string 's' */
|
||||
int mystrlen(char s[])
|
||||
{
|
||||
int len;
|
||||
for (len = 0; s[len] != '\0'; ++len)
|
||||
;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* reads (possibly truncated) line from input to s, returns \n or EOF */
|
||||
int get_line(char s[], int maxline)
|
||||
{
|
||||
int c, i;
|
||||
|
||||
for (i=0; (c=getchar()) != EOF && c != '\n'; ++i) {
|
||||
if (i < maxline)
|
||||
s[i] = c;
|
||||
}
|
||||
|
||||
if (i < maxline)
|
||||
s[i] = '\0';
|
||||
else
|
||||
s[maxline] = '\0';
|
||||
|
||||
return c;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define TABSTOP 4
|
||||
|
||||
void detab(int tabstop);
|
||||
int fill(int indent, int tabstop);
|
||||
|
||||
/* detab input, takes one optional argument for tabstop width */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int tabstop;
|
||||
|
||||
if (argc < 2 || !(tabstop = atoi(argv[1])))
|
||||
detab(TABSTOP);
|
||||
else
|
||||
detab(tabstop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* detabs input with spaces, tab stop width is 'tabstop' */
|
||||
void detab(int tabstop)
|
||||
{
|
||||
int c, indent = 0; /* indent starts at 0 */
|
||||
|
||||
while ((c = getchar()) != EOF)
|
||||
if (c == '\t')
|
||||
indent = fill(indent, tabstop);
|
||||
else {
|
||||
putchar(c);
|
||||
indent = (c == '\n') ? 0 : indent + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* fills output with spaces from indent to next tabstop */
|
||||
/* returns new indent */
|
||||
int fill(int indent, int tabstop)
|
||||
{
|
||||
int w = tabstop - indent % tabstop;
|
||||
|
||||
for (; w > 0; --w) {
|
||||
putchar(' ');
|
||||
++indent;
|
||||
}
|
||||
|
||||
return indent;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define TABSTOP 4
|
||||
|
||||
void entab(int tabstop);
|
||||
|
||||
/* entab input, takes one optional argument for tabstop width */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int tabstop;
|
||||
|
||||
if (argc < 2 || !(tabstop = atoi(argv[1])))
|
||||
entab(TABSTOP);
|
||||
else
|
||||
entab(tabstop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* entabs input with spaces, tab stop width is 'tabstop' */
|
||||
void entab(int tabstop)
|
||||
{
|
||||
int c, indent; /* indent starts at 1 */
|
||||
int bn = 0; /* current number of blanks */
|
||||
|
||||
for (indent = 1; (c = getchar()) != EOF; ++indent)
|
||||
if (c == ' ') {
|
||||
if (indent % tabstop || bn == 0)
|
||||
/* dont entab single spaces */
|
||||
++bn;
|
||||
else {
|
||||
bn = 0;
|
||||
putchar('\t');
|
||||
}
|
||||
} else {
|
||||
for(; bn > 0; --bn)
|
||||
putchar(' ');
|
||||
putchar(c);
|
||||
if (c == '\n')
|
||||
indent = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TABSTOP 8
|
||||
#define WIDTH 80
|
||||
// the RATIO can't be less than 1/2
|
||||
#define RATIO 2.0/3.0
|
||||
#define BREAKSTR "-"
|
||||
|
||||
int bstrlen = strlen(BREAKSTR);
|
||||
|
||||
void fold(int width, int maxind);
|
||||
void flush_wbuff(int wbi, char wbuff[]);
|
||||
int insert_break(char buff[], int wbi);
|
||||
int is_blank(char c);
|
||||
int mv_cur(int n, char c);
|
||||
|
||||
/* fold input, takes one optional argument for max line width (excl \n) */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int w;
|
||||
|
||||
if (argc < 2 || (w = atoi(argv[1])) < 2)
|
||||
fold(WIDTH, RATIO * WIDTH);
|
||||
else
|
||||
fold(w, RATIO * w);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* folds input lines to length, where minw <= length <= 'width'
|
||||
* if a line has no blank spaces after 'minw' chars a BREAKSTR is inserted */
|
||||
void fold(int width, int minw)
|
||||
{
|
||||
int c, n = 0; // n=0 is start of line
|
||||
int wbi = 0; // word buffer index
|
||||
char wbuff[width - minw]; // word buffer for words over minw
|
||||
|
||||
while ((c = getchar()) != EOF) {
|
||||
n = mv_cur(n, c);
|
||||
|
||||
if (c == '\n' || (n >= width+1 && is_blank(c))) {
|
||||
// handle newlines
|
||||
flush_wbuff(wbi, wbuff);
|
||||
putchar('\n');
|
||||
n = wbi = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n <= minw) // always print chars before minw
|
||||
putchar(c);
|
||||
else if (n <= width) {
|
||||
/* add word (optionaly leading blank) after minw to wbuff
|
||||
* empty buffer if new blank is found */
|
||||
if (is_blank(c)) {
|
||||
flush_wbuff(wbi, wbuff);
|
||||
wbi = 0;
|
||||
}
|
||||
wbuff[wbi] = c;
|
||||
++wbi;
|
||||
} else { // one char over edge, c != ' '
|
||||
n = insert_break(wbuff, wbi) + 1;
|
||||
putchar(c);
|
||||
wbi = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flush_wbuff(int wbi, char wbuff[])
|
||||
{
|
||||
printf("%.*s", wbi, wbuff);
|
||||
}
|
||||
|
||||
/* print buff and insert line break where its most fitting,
|
||||
* return new cursor position
|
||||
* '\n' is inserted before the last word or 'BREAKSTR\n' is inserted */
|
||||
int insert_break(char wbuff[], int wbi)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (wbi == 0) {
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_blank(wbuff[0])) {
|
||||
putchar('\n');
|
||||
for (i=1; i < wbi; ++i)
|
||||
putchar(wbuff[i]);
|
||||
return wbi - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
flush_wbuff(wbi-bstrlen, wbuff);
|
||||
printf("%s\n", BREAKSTR);
|
||||
for (i = wbi-bstrlen; i < wbi; ++i)
|
||||
putchar(wbuff[i]);
|
||||
return bstrlen;
|
||||
}
|
||||
|
||||
/* return new cursor position */
|
||||
int mv_cur(int n, char c)
|
||||
{
|
||||
if (c == '\t')
|
||||
return n + (TABSTOP - n % TABSTOP);
|
||||
else if (c == '\b')
|
||||
return n;
|
||||
return n+1;
|
||||
}
|
||||
|
||||
int is_blank(char c)
|
||||
{
|
||||
return (c == ' ' || c == '\t');
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
#include <stdio.h>
|
||||
#define MAXBUFF 100
|
||||
|
||||
void ignore_line(void);
|
||||
int ignore_multiline(void);
|
||||
int pass_char_const(char fst);
|
||||
int pass_string(char fst);
|
||||
|
||||
int flush_buff(char buff[], int bi);
|
||||
int is_blank(char c);
|
||||
|
||||
/* remove comments from input; remove empty lines and trailing spaces
|
||||
* left by removed comments; Check for the following errors:
|
||||
* - invalid string literals
|
||||
* - invalid char constants
|
||||
* - non-terminating multi line comments */
|
||||
int main()
|
||||
{
|
||||
int a, b;
|
||||
|
||||
int bi = 0; // blank buffer index
|
||||
char blank_buff[MAXBUFF]; // blank buffer
|
||||
|
||||
for (a = getchar(); (b = getchar()) != EOF; a = b)
|
||||
if (a == '/' && b == '*') {
|
||||
bi = 0;
|
||||
if (ignore_multiline()) {
|
||||
printf("\nerror : no terminator for multiline comment\n");
|
||||
return 1;
|
||||
}
|
||||
b = getchar();
|
||||
} else if (a == '/' && b == '/') {
|
||||
bi = 0;
|
||||
ignore_line();
|
||||
putchar('\n');
|
||||
b = getchar();
|
||||
} else if (a == '\'') {
|
||||
bi = flush_buff(blank_buff, bi);
|
||||
putchar('\'');
|
||||
if (pass_char_const(b)) {
|
||||
printf("\nerror : invalid character constant\n");
|
||||
return 1;
|
||||
}
|
||||
b = getchar();
|
||||
} else if (a == '"') {
|
||||
bi = flush_buff(blank_buff, bi);
|
||||
putchar('"');
|
||||
if (pass_string(b)) {
|
||||
printf("\nerror : invalid string literal\n");
|
||||
return 1;
|
||||
}
|
||||
b = getchar();
|
||||
} else if (is_blank(a)) {
|
||||
if (bi >= MAXBUFF)
|
||||
bi = flush_buff(blank_buff, bi);
|
||||
blank_buff[bi] = a;
|
||||
++bi;
|
||||
} else if (a == '\n') {
|
||||
flush_buff(blank_buff, bi);
|
||||
blank_buff[0] = a;
|
||||
bi = 1;
|
||||
} else {
|
||||
bi = flush_buff(blank_buff, bi);
|
||||
putchar(a);
|
||||
}
|
||||
|
||||
if (a != EOF)
|
||||
putchar(a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ignore line of input */
|
||||
void ignore_line()
|
||||
{
|
||||
int c;
|
||||
while ((c = getchar()) != EOF && c != '\n')
|
||||
;
|
||||
}
|
||||
|
||||
/* ignore input until comment termination occurs
|
||||
* return 1 if error otherwise 0 */
|
||||
int ignore_multiline()
|
||||
{
|
||||
int a, b;
|
||||
for (a = getchar(); (b = getchar()) != EOF; a = b)
|
||||
if (a == '*' && b == '/')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* pass the tail of a character constant from input to ouput
|
||||
* return 1 if error otherwise 0 */
|
||||
int pass_char_const(char fst)
|
||||
{
|
||||
int c;
|
||||
|
||||
putchar(fst);
|
||||
if (fst == '\\') {
|
||||
if ((c = getchar()) == EOF)
|
||||
return 1;
|
||||
putchar(c);
|
||||
}
|
||||
if ((c = getchar()) == EOF || c != '\'')
|
||||
return 1;
|
||||
putchar(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* pass the tail (wihtout fst element) of a
|
||||
* C string literal from input to output.
|
||||
* 'fst' is the first character of the string tail
|
||||
* return 1 if error otherwise 0 */
|
||||
int pass_string(char fst)
|
||||
{
|
||||
int snd;
|
||||
|
||||
putchar(fst);
|
||||
for (; (snd = getchar()) != EOF; fst = snd) {
|
||||
putchar(snd);
|
||||
if (fst == '\n')
|
||||
break;
|
||||
if (snd == '"' && fst != '\\')
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* print buffer 'buff' and return 0 */
|
||||
int flush_buff(char buff[], int bi)
|
||||
{
|
||||
printf("%.*s", bi, buff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_blank(char c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\b';
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TABSTOP 8
|
||||
#define BUFFSIZE 100
|
||||
#define ESCAPED "0bnt\\"
|
||||
#define LINEN 5
|
||||
|
||||
#define ERRMSG_SIZE 100
|
||||
#define ERR_ESC_EOF "expected escape character, got EOF"
|
||||
#define ERR_ESC_INV "invalid escape character"
|
||||
#define ERR_STR_TRM "expected string termination"
|
||||
#define ERR_CHAR_EOF "expected character constant, got EOF"
|
||||
#define ERR_CHAR_TRM "expected character constant termination"
|
||||
#define ERR_COMM_TRM "expected multi-line comment termination"
|
||||
|
||||
/* global input line and character counting */
|
||||
int ln = 1;
|
||||
int cn = 0;
|
||||
int ln_getchar()
|
||||
{
|
||||
int c;
|
||||
if ((c = getchar()) == '\n' || c == EOF) {
|
||||
cn = 0;
|
||||
++ln;
|
||||
} else
|
||||
++cn;
|
||||
return c;
|
||||
}
|
||||
#define getchar() ln_getchar()
|
||||
|
||||
int print_context();
|
||||
|
||||
int check_escaped(char errmsg[], int d);
|
||||
int check_multiline(char errmsg[]);
|
||||
int check_char_const(char errmsg[]);
|
||||
int check_string(char errmsg[]);
|
||||
|
||||
int getcharb();
|
||||
int ithchar(int i);
|
||||
int prevchar();
|
||||
int print_buff(int n);
|
||||
|
||||
void print_line();
|
||||
void ignore_line();
|
||||
void copy(char from[], char to[]);
|
||||
|
||||
/* check c program on input for unabalanced parantheses
|
||||
* string termination, comment termination and char constant
|
||||
* validity */
|
||||
int main()
|
||||
{
|
||||
int i, c;
|
||||
int err = 0;
|
||||
char errmsg[ERRMSG_SIZE];
|
||||
|
||||
|
||||
while (!err && (c = getcharb()) != EOF) {
|
||||
if (c == '"' && check_string(errmsg)) {
|
||||
err = 1;
|
||||
} else if (c == '\'' && check_char_const(errmsg)) {
|
||||
err = 2;
|
||||
} else if (prevchar() == '/' && c == '*' && check_multiline(errmsg)) {
|
||||
err = 3;
|
||||
} else if (c == '/' && prevchar() == '/') {
|
||||
ignore_line();
|
||||
}
|
||||
}
|
||||
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
int li = print_context();
|
||||
printf("%d:%d: error: %s\n", ln-1, li+1, errmsg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* print context of error and arrow pointing to cursor
|
||||
* position where error was raised */
|
||||
int print_context()
|
||||
{
|
||||
int i, li = print_buff(LINEN);
|
||||
|
||||
if (li < 0) {
|
||||
for (i = li; i < -1; ++i)
|
||||
putchar(' ');
|
||||
} else {
|
||||
print_line();
|
||||
for (i = li; i > 0; --i)
|
||||
putchar(' ');
|
||||
}
|
||||
printf("^\n");
|
||||
return li;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------- validation functions ------------------------
|
||||
/* check multiline comment termination */
|
||||
int check_multiline(char errmsg[])
|
||||
{
|
||||
int c;
|
||||
while ((c = getcharb()) != EOF)
|
||||
if (prevchar() == '*' && c == '/')
|
||||
return 0;
|
||||
copy(ERR_COMM_TRM, errmsg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check char constant validity and termination */
|
||||
int check_char_const(char errmsg[])
|
||||
{
|
||||
int c;
|
||||
|
||||
if ((c = getcharb()) == EOF) {
|
||||
copy(ERR_CHAR_EOF, errmsg);
|
||||
return 1;
|
||||
}
|
||||
if (c == '\\' && check_escaped(errmsg, '\''))
|
||||
return 1;
|
||||
if ((c = getcharb()) == EOF || c != '\'') {
|
||||
copy(ERR_CHAR_TRM, errmsg);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check string termination */
|
||||
int check_string(char errmsg[])
|
||||
{
|
||||
int c;
|
||||
while ((c = getcharb()) != EOF && c != '\n') {
|
||||
if (c == '\\' && check_escaped(errmsg, '"'))
|
||||
return 1;
|
||||
else if (c == '"')
|
||||
return 0;
|
||||
}
|
||||
copy(ERR_STR_TRM, errmsg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check if \(next input char) makes a valid escape char
|
||||
* \'d' is considered valid, pass negative 'd' to make optional */
|
||||
int check_escaped(char errmsg[], int d)
|
||||
{
|
||||
int i, c = getcharb();
|
||||
|
||||
if (c == EOF) {
|
||||
copy(ERR_ESC_EOF, errmsg);
|
||||
return 1;
|
||||
}
|
||||
if (c == d)
|
||||
return 0;
|
||||
for (i = 0; i < strlen(ESCAPED); ++i)
|
||||
if (ESCAPED[i] == c)
|
||||
return 0;
|
||||
copy(ERR_ESC_INV, errmsg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------- buffered input -------------------------
|
||||
int ibi = 0;
|
||||
int iblen = 0;
|
||||
int ibtrunc = 0
|
||||
/* cyclic input stream buffer
|
||||
* 'ibi' is the current buffer index
|
||||
* 'iblen' is the buffer length
|
||||
* 'ibtrunc' is the number of characters truncated
|
||||
* from first line in buffer */
|
||||
char in_buff[BUFFSIZE];
|
||||
|
||||
|
||||
|
||||
/* get char from input, put it in buffer and return it
|
||||
* otherwise same as getchar */
|
||||
int getcharb()
|
||||
{
|
||||
int c;
|
||||
if ((c = getchar()) == EOF)
|
||||
return EOF;
|
||||
ibtrunc = (iblen == BUFFSIZE && in_buff[ibi] == '\n') ? 0 : ibtrunc + 1;
|
||||
in_buff[ibi] = c;
|
||||
++ibi;
|
||||
if (iblen < BUFFSIZE)
|
||||
++iblen;
|
||||
else if (ibi >= BUFFSIZE)
|
||||
ibi = 0;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* return ith char of buffer indexed from 'ibi'
|
||||
* doesnt check validity of i */
|
||||
int ithchar(int i)
|
||||
{
|
||||
int ri = ibi + i; // real index
|
||||
return (ri < iblen) ? in_buff[ri] : in_buff[ri - iblen];
|
||||
}
|
||||
|
||||
/* returns second last buffered input char
|
||||
* if there is none return -1 */
|
||||
int prevchar()
|
||||
{
|
||||
return (iblen > 1) ? ithchar(iblen-2) : -1;
|
||||
}
|
||||
|
||||
|
||||
/* return the (relative) index of the start of relevant context in buffer */
|
||||
int context_start(int n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ----------------------- utility functions --------------------------
|
||||
/* ignore line of input */
|
||||
void ignore_line()
|
||||
{
|
||||
int c;
|
||||
while ((c = getcharb()) != EOF && c != '\n')
|
||||
;
|
||||
}
|
||||
|
||||
/* print first line of input */
|
||||
void print_line()
|
||||
{
|
||||
int c;
|
||||
while ((c = getchar()) != EOF && c != '\n')
|
||||
putchar(c);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/* copy from 'from' to 'to'
|
||||
* 'to' must be large enough */
|
||||
void copy(char from[], char to[])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; from[i] != '\0'; ++i)
|
||||
to[i] = from[i];
|
||||
to[i] = '\0';
|
||||
}
|
Loading…
Reference in New Issue