Emit INDENT/OUTDENT tokens from Flex - c

I have found a great example of handling Python-style INDENT/OUTDENT in Flex here: http://matt.might.net/articles/standalone-lexers-with-lex/
The code is:
%{
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#define MAX_DEPTH 72
int nesting = 0 ;
unsigned int indent_stack[MAX_DEPTH] ;
unsigned int level = 0 ;
unsigned int first = 1 ;
void process_indent(char* line) ;
%}
PUNCT [-+*/=<>:]*
ID [A-Za-z_][A-Za-z0-9_]*
INT [0-9]+
%option noyywrap
%%
^[ ]*\n {/* Ignore blank lines. */}
^[ ]*[^ \n]+ {int last = yyleng - 1;
process_indent(yytext) ;
while ((last >= 0) &&
(yytext[last] != ' ')) {
unput(yytext[last]);
last-- ;}}
"(" {printf(" "); ECHO; nesting++ ; }
")" {printf(" "); ECHO; nesting-- ; }
{ID}|{INT}|{PUNCT} {printf(" ") ; ECHO;}
[ \r] {}
\n {}
<<EOF>> { process_indent("") ; return 0 ; }
%%
unsigned int white_count(char* line) {
unsigned int count = 0 ;
while (*line == ' ')
count++, line++ ;
return count ;
}
void process_indent(char* line) {
if (nesting)
/* Ignore indents while nested. */
return ;
unsigned int indent = white_count(line) ;
if (indent == indent_stack[level]) {
if (!first) printf(" ;") ; // EMIT END_STATEMENT
first = 0 ;
return ;
}
if (indent > indent_stack[level]) {
printf(" {") ; // EMIT BLOCK_START
assert(level+1 < MAX_DEPTH) ;
indent_stack[++level] = indent ;
return ;
}
while (indent < indent_stack[level]) {
--level ;
printf(" }") ; // EMIT BLOCK_END
}
assert(level >= 0) ;
}
int main(int argc, char* argv[]) {
indent_stack[0] = 0 ;
yylex() ;
printf("\n") ;
}
Basically, it converts code like this:
def f(x):
y = x * x
e = (m * c
* c)
if x > 0:
return e
else:
return y
To this:
def f ( x ) : { y = x * x ; e = ( m * c * c ) ;
if x > 0 : { return e } else : { return y } }
Which is exactly what I need. With one difference: I want the lexer to return the appropriate tokens instead of printing out the curly braces.
The problem is with the OUTDENTs. This happens in a while block in the process_indent function (meaning: there may be more than one block to "close"). And that means I would have to return more than one tokens at the same time - which is NOT possible with Lex/Flex.
Any ideas how I could change that to make it work? Are there any working examples with what I need?

Any ideas how I could change that to make it work? Are there any
working examples with what I need?
You could base your code on the Python lexer example included with RE/flex, see ptokens.l. This lexer fully supports Python's syntax rules such as indentation blocks, and implicit and explicit line joining which isn't possible with process_indent(). Multiple "OUTDENT" (RE/flex "dedent") are generated when multiple blocks close.
The example requires RE/flex as a more advanced version of Flex. But RE/flex is very much like Flex and accepts Flex specifications, so moving on to RE/flex should be easy.

Related

c program prints question mark in a box as an output

There is a char pointer variable, and its value coming from a function.
char* apple = ....(function call)
I wanted to print this as follows:
int len = strlen(apple);
for(i=0;i<len;i++){
printf("%c ", apple[i]);
}
But in the console, it gives a question mark in a box as an output. What should I do, how should I print it? Thanks.
I dont see issue in the printing part, through the fucntion that retuns pointer to char array needs to be investigatd.
// In this example, getString function returns string literal
// That is being iterated in the next for loop over its length and prints its characters
#include <stdio.h>
#include <stdlib.h>
char *getString(void); // declare
int main() {
char *apple = getString();
int len = strlen(apple);
for(int i = 0; i < len ; i++) {
printf("%c ", apple[i]);
}
return 0;
}
char *getString() {
return "somesthing";
}
Below example will print only printable ascii chars. From 0 to 31 , 0 is for null, 1 is for SOH and so on. Simply you cannot print control codes (ASCII codes < 32) if you print strange output is expected.
#include <stdio.h>
#include <string.h>
#define PRINTABLE_ASCII_CHAR_COUNT 96
/*
Printable chars list
"! " # $ % & ' ( ) * + , - . /
0 1 2 3 4 5 6 7 8 9 : ; < = > ?
# A B C D E F G H I J K L M N O
P Q R S T U V W X Y Z [ \ ] ^ _
` a b c d e f g h i j k l m n o
p q r s t u v w x y z { | } ~"
*/
char *getASCIIs(void);
int main() {
char *apple = getASCIIs();
int len = strlen(apple);
for(int i = 0; i < len ; i++) {
// p << i << ((i % 16 == 15) ? '\n' : ' ');
printf("%c ", apple[i]);
}
return 0;
}
char *getASCIIs() {
static char buffer[PRINTABLE_ASCII_CHAR_COUNT];
for (int i = 32, j=0 ; i <= PRINTABLE_ASCII_CHAR_COUNT; i++, j++) {
buffer[j] = i;
}
return buffer;
}
enter code here
Your syntax seems legit. I highly suspect that cigar[i] donates the proper character that you are looking for. Trying affirming that by casting cigar[i] into a character using (char) cigar[i]. You might output cigar[i] as a string %s as a part of debugging where does it really point at.

maze generation algorithm in c with DFS

recently i read this topic about generating mazes in c . see here https://www.algosome.com/articles/maze-generation-depth-first.html
and i want to write it in c . here is my code and it's not working right .
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int check[5][5];
int v[5][5];
int border(int x , int y ){
if(x> -1 && x< 6 && y > -1 && y<6)
return 1;
else
return 0 ;
}
int wall[6][6][6][6];
void dfs ( int x , int y){
srand(time(NULL));
int s = 1/*rand() % 4 ;*/ ;
if(s=1 ){
if(border(x ,y-1)&& check[x][y-1]==0){
check[x][y]=1;
wall[x][y][x+1][y]=1;
dfs(x , y-1);
}
else
return ;
}
else if(s=2){
if(border(x+1 ,y)&&check[x+1][y]==0){
check[x][y]=1;
wall[x+1][y][x+1][y+1]=1;
dfs(x+1 , y);
}
else return ;
}
else if(s=3){
if(border(x ,y+1)&&check[x][y+1]==0){
check[x][y]=1;
wall[x][y+1][x+1][y+1]=1;
dfs(x , y+1);
}
else return ;
}
else if(s=0){
if(border(x-1 ,y)&&check[x-1][y]==0){
check[x][y]=1;
wall[x][y][x][y+1]=1;
dfs(x-1 , y);
}
else return ;
}
return ;
}
int main(){
dfs( 4, 4);
for(int i =0 ; i < 6 ; i++)
for (int j =0 ; j < 6 ; j++)
for ( int h =0 ; h <6 ; h++)
for (int k =0 ; k < 6 ; k ++)
printf("%d \n" , wall[i][j][h][k]);
return 0 ;
}
i invert my table to graph , and i want to show me the coordinates of my walls .
what's the problem ?
You have several errors – programming errors and logic errors – in your code:
When you distiguish between the directions the s=1 and so on should be s == 1. You want a comparison, not an assignment. (Your code is legal C, so there is no error.)
You call srand at the beginning of dfs, which you call recursively. This will make your single (commented) rand call always create the same random number. You should seed the pseudo random number generator only once at the beginning of main.
You can store the paths the way you do, but it is wasteful. There are only four possible paths from each cell, so you don't need an array that allows to create a path between (0,0) and (3,4), for example.
Your code would benefit from using constants or enumerated values instead of the hard-coded 5's and 6's. This will allow you to change the dimensions later easily.
But your principal error is in how you implement the algorithm. You pick one of the for directions at random, then test whether that direction leads to a valid unvisited cell. If so, you recurse. If not, you stop. This will create a single unbranched path through the cells. Note that if you start in a corner cell, you have already a 50% chance of stopping the recursion short.
But you want something else: You want a maze with many branches that leads to every cell in the maze. Therefore, when the first recursion returns, you must try to branch to other cells. The algorithm goes like this:
Make a list of all possible exits.
If there are possible exits:
Pick one exit, create a path to that exit and recurse.
Update the list of possible exits.
Note that you cannot re-use the old list of exits, because the recursion may have rendered some possible exits invalid by visiting the destination cells.
Below is code that creates a maze with the described algorithm. I've used two distinct arrays to describe horizontal and vertical paths:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
enum {
W = 36, // width of maze
H = 25 // height of maze
};
enum {
North,
East,
South,
West,
NDir
};
char visited[H][W];
char horz[H][W - 1]; // horizontal E-W paths in the maze
char vert[H - 1][W]; // veritcal N-S paths in the maze
/*
* Fill dir with directions to unvisited cells, return count
*/
int adjacent(int dir[], int x, int y)
{
int ndir = 0;
if (y > 0 && visited[y - 1][x] == 0) dir[ndir++] = North;
if (x < W - 1 && visited[y][x + 1] == 0) dir[ndir++] = East;
if (y < H - 1 && visited[y + 1][x] == 0) dir[ndir++] = South;
if (x > 0 && visited[y][x - 1] == 0) dir[ndir++] = West;
return ndir;
}
/*
* Traverse cells depth first and create paths as you go
*/
void dfs(int x, int y)
{
int dir[NDir];
int ndir;
visited[y][x] = 1;
ndir = adjacent(dir, x, y);
while (ndir) {
int pick = rand() % ndir;
switch (dir[pick]) {
case North: vert[y - 1][x] = 1; dfs(x, y - 1); break;
case East: horz[y][x] = 1; dfs(x + 1, y); break;
case South: vert[y][x] = 1; dfs(x, y + 1); break;
case West: horz[y][x - 1] = 1; dfs(x - 1, y); break;
}
ndir = adjacent(dir, x, y);
}
}
/*
* Print a map of the maze
*/
void map(void)
{
int i, j;
for (i = 0; i < W; i++) {
putchar('_');
putchar('_');
}
putchar('\n');
for (j = 0; j < H; j++) {
putchar('|');
for (i = 0; i < W; i++) {
putchar(j < H - 1 && vert[j][i] ? ' ' : '_');
putchar(i < W - 1 && horz[j][i] ? '_' : '|');
}
putchar('\n');
}
}
int main()
{
srand(time(NULL));
dfs(0, 0);
map();
return 0;
}
You can test it here. If you replace the while in dsf with a simple if, you get more or less what you implemented. Note that this creates only a single, usually short path.

Minesweeper game

do you know the minesweeper game of windows . well , the following problem is the same , you will input m and n ...
0 < n,m <= 100
n : colons , m : rows
input :
4 4
*...
....
.*..
....
output :
*100
2210
1*10
1110
and , that is my code .
#include <stdio.h>
#include <stdlib.h>
char ms[100][101] ;
int m , n;
void input(){
for(int r = 0 ; r < m ; r++)
for(int c = 0 ; c <= n ; c++){
scanf("%c",&ms[r][c]);
if('.' == ms[r][c])
ms[r][c] += 2 ;
}
}
void calc(int m , int n){
for(int r = m ; r <= (m+2) ; r++)
for(int c = n ; c <= (n+2) ; c++)
if(r >= 0 && c >= 0 && ms[r][c] != '*')
ms[r][c] += 1 ;
}
void solve(){
for(int r = 0 ; r < m ; r++)
for(int c = 0 ; c < n ; c++)
if( '*' == ms[r][c])
calc(r-1 , c-1);
}
void output(){
for(int r = 0 ; r < m ; r++)
for(int c = 0 ; c <= n ; c++)
printf("%c ", ms[r][c]);
}
int main()
{
scanf("%d%d" , &m , &n);
input();
solve();
output();
return 0;
}
when running my code , if the input have * at the first as follows :
4 4
*...
....
.*..
....
the output is :
important to see it .. click here
note: i tried to print the value of the symbol that appeard in the picture and it is 11 in ascii code which is vertical tab.
and , another problem if the * is at the last as follows :
4 4
...*
....
....
...*
000*
0000
0000
000*
but my code works well when the * is at the middle as follows :
4 4
....
..*.
.*..
....
0111
12*1
1*21
1110
so , what's the problem with my code ?
In this line you can go out of bounds:
if(r >= 0 && c >= 0 && ms[r][c] != '*')
ms[r][c] += 1 ;
You only test if r and c are not negative, but you should also test they are not too large.
The thing becomes more complicated because you have global variables m and n which are the dimensions of your array, but they are not available in the calc function, because there you have local variables with the same name.
So you better use different variable names. And then you should test that r<m and c<n, as follows:
void calc(int p , int q){
for(int r = p ; r <= (p+2) ; r++)
for(int c = q ; c <= (q+2) ; c++)
if(r >= 0 && c >= 0 && r < m && c < n && ms[r][c] != '*')
ms[r][c] += 1 ;
}
Now the reason you saw an ASCII 11 is explained by the fact that ASCII 10 is the line feed character that marks the end of a row. Then when your code performs ms[r][c] += 1 on it (because it goes too far), it becomes that funny character.
That you have that ASCII 10 in your array is explained by how you read the input (see #pmg's answer). If you would not have read those white space characters, you would still overrun, and probably touch data in a next row of data, which is not what you want to happen.
scanf("%d", ...);
leaves whitespace (the ENTER) in the input buffer. Then
scanf("%c", ...);
reads that whitespace into the variable.
You need to ignore the whitespace before (and during) reading the stars and dots.
Use
scanf(" %c", ...);
// ^^^ ignore whitespace
Note: the conversion specifier "%d" (and many others) already includes ignoring whitespace; the exceptions are "%c", "%[", and [for different reasons] "%n").

One of my value in array gives "0"

In my file includes two columns and I'm try to gather data from file. I need to compare two value in one column. For example, if array[5] is higher than array[4], do something. Here my code:
int control(double col2[], double col3[], int subscript){
double a, b, fcontrol ;
int k /* group */ ;
/* some necessary values for JD controlling */
a = col2[subscript] ;
b = col2[subscript-1] ;
/* for JD controlling */
fcontrol = a - b ;
printf("kontrol = %.12f a = %.12f b = %.12f\n", fcontrol, a, b) ;
/* if value of between two data is equal or higher than 10 hour return 1 */
if(fcontrol >= 0.416666666667){
return 1 ;
}
else{
return 0 ;
}
b is always 0. How can I fix it?
My terminal is :
kontrol = 258.426728989849 a = 258.426728989849 b = 0.000000000000
kontrol = 258.447161800788 a = 258.447161800788 b = 0.000000000000
kontrol = 258.467594711488 a = 258.467594711488 b = 0.000000000000
kontrol = 260.245248070103 a = 260.245248070103 b = 0.000000000000
kontrol = 260.265680861012 a = 260.265680861012 b = 0.000000000000
kontrol = 260.286113551461 a = 260.286113551461 b = 0.000000000000
kontrol = 260.306546441912 a = 260.306546441912 b = 0.000000000000
Here my all code :
/* TASK */
#include<stdio.h>
int kontrol(double col2[], double col3[], int subscript) ;
int main(){
int kolon1,
n = 0, /* for array */
j, z, /* for "for" loopr */
flag = 0 ;
int grup = 0 ;
double kolon2, kolon3,
col2[100000], col3[100000] ;
char ignore[100];
FILE *okuPtr ;
FILE *yazPtr ;
char oku_tbl[100] ;
sprintf(oku_tbl, "deneme.tbl") ;
/* error if file isnt opened*/
if ((okuPtr = fopen(oku_tbl, "r")) == NULL)
printf("%s Acilamadi", oku_tbl) ;
/* file is opened */
else{
char yaz_tbl[100] ;
sprintf(yaz_tbl, "deneme_data.tbl") ;
/* errof if file isnt opened */
if((yazPtr = fopen(yaz_tbl, "w")) == NULL)
printf("%s acilamadi\n", yaz_tbl) ;
/* file is opened */
else{
/* first read */
fscanf(okuPtr, "%d%lf%lf", &kolon1, &kolon2, &kolon3) ;
/* until end of file */
while (!feof(okuPtr)){
/* ignore first 3 line */
fgets(ignore, 100, okuPtr) ;
col2[n] = kolon2 ;
col3[n] = kolon3 ;
flag = control(col2, col3, n) ;
n++ ;
/* if flag == 1 */
if (flag == 1){
for (z = 0 ; z <= --n ; z++){
fprintf(yazPtr, "%d\t%.12f\t%.12f\n", grup, col2[z], col3[z]) ;
}
n = 0 ;
grup++ ;
}
/* yeni veri oku */
fscanf(okuPtr, "%d%lf%lf", &kolon1, &kolon2, &kolon3) ;
}
/* diziyi yazdir
for (j = 0 ; j <= n-1 ; j++){
printf("%d\t%-.12f\t%-.12f\n", k, col2[j], col3[j]) ;
} */
}
}
return 0 ;
}
int control(double col2[], double col3[], int subscript){
double a, b,
fcontrol ;
int k /* group */ ;
/* some necessary values for JD controlling */
a = col2[subscript] ;
b = col2[subscript-1] ;
/* for JD controlling */
fcontrol = a - b ;
printf("kontrol = %.12f a = %.12f b = %.12f\n", fcontrol, a, b) ;
/* if value of between two data is equal or higher than 10 hour return 1 */
if(fcontrol >= 0.416666666667){
return 1 ;
}
else{
return 0 ;
}
}
Problem is that when you call control for first time when n=0
flag = control(col2,col3, n);
But notice here b=col2[subscript-1] will actually be b=col2[-1] which is creating problem as array indexing start with 0 thus your program has this behaviour .
while (!feof(okuPtr))
It is always wrong. See here-Why is “while ( !feof (file) )” always wrong?
Instead use this -
while(fgets(ignore, 100, okuPtr))
{
/*Your code*/
}

csv line parsing, printing extra line at end

I have been supplied a CSV line parser to use in a program, and it seems to have a bug where if there is a blank line at the end of the text file it prints out an empty line, like so
My input is this
test, does, this, work
1, second, line, same
My output looks like this. Not only does it cut off the last word, but it prints out the empty line.
test = 1
does = second
this = line
work = same
test =
What it's supposed to do is match every word with the coinciding one in the top line, which it does, but I don't know where the last "test = " is coming from. Here's the code I was supplied, any ideas about what's wrong with it would be a huge help. Thanks.
/*
* Just an array of characters representing a single filed.
*/
typedef char f_string[MAX_CHARS+1] ; /* string for each field */
/*
* A parsed CSV line, with the number of fields and upto MAX_FIELDS themselves.
*/
typedef struct {
int nfields ; /* 0 => end of file */
f_string field[MAX_FIELDS] ; /* array of strings for fields */
} csv_line ;
/*
* Returns true iff the character 'ch' ends a field. That is, ch is end of file,
* a comma, or a newline.
*/
bool is_end_of_field(char ch) {
return (ch == ',') || (ch == '\n') || (ch == EOF) ;
}
/*
* Return the minimum of two integers.
*/
int min(int x, int y) {
return x < y ? x : y ;
}
/*
* Read the next field from standard input. Returns the value of getchar() that
* stopped (terminated) the field.
*/
int get_field(f_string field) {
/**BEGIN_SOLN**/
int i ;
int next_char ;
next_char = getchar() ;
for ( i = 0 ; ! is_end_of_field(next_char) ; ++i ) {
field[i] = next_char ;
next_char = getchar() ;
}
field[i] = '\0' ;
return next_char ;
/**END_SOLN**/
}
/*
* Read in a CSV line. No error checking is done on the number of fields or
* the size of any one field.
* On return, the fields have been filled in (and properly NUL-terminated), and
* nfields is the count of the number of valid fields.
* nfields == 0 means end of file was encountered.
*/
csv_line get_line() {
/**BEGIN_SOLN**/
csv_line line ;
int fi = 0 ; /* index of current field in line */
int stop_ch ; /* character that terminated the last field */
stop_ch = get_field(line.field[fi++]) ;
while ( stop_ch == ',' ) {
stop_ch = get_field(line.field[fi++]) ;
}
line.nfields = (stop_ch == EOF) ? 0 : fi ;
return line ;
/**END_SOLN**/
}
/*
* Print a CSV line, associating the header fields with the
* data line fields.
* The minimum of the number of fields in the header and the data
* determines how many fields are printed.
*/
void print_csv(csv_line header, csv_line data) {
/**BEGIN_SOLN**/
int i ;
int nfields = min(header.nfields, data.nfields) ;
for ( i = 0 ; i < nfields ; ++i ) {
printf("%s = %s\n", header.field[i], data.field[i]) ;
}
/**END_SOLN**/
}
/*
* Driver - read a CSV line for the header then read and print data lines
* until end of file.
*/
int main() {
csv_line header ;
csv_line current ;
header = get_line() ;
current = get_line() ;
while ( current.nfields > 0 ) {
print_csv(header, current) ;
current = get_line() ;
}
return 0 ;
}
bool is_end_of_field(int ch) {
return (ch == ',') || (ch == '\n') || (ch == EOF) ;
}
bool get_field(f_string field){
int i ;
int next_char ;
for ( i = 0 ; ! is_end_of_field(next_char=getchar()) ; ++i ) {
field[i] = next_char ;
}
field[i] = '\0';
return (next_char == ',')? true : false;
}
csv_line get_line() {
csv_line line ;
int fi = 0;
while(get_field(line.field[fi++]))
;
line.nfields = line.field[fi-1][0] ? fi : 0;
return line ;
}

Resources