How to re-launch the scan in LEX - lex

I am trying to do a conversor from markdown syntax to Latex and vice versa. But I am facing a problem I can not solve so far. Lets say, we have the following text:
* item
* item
* _Italic_ item
* Item with __nested _italic_ text__
Right now, my lex program would do this to the text:
\begin{itemize}
\item{item}
\item{item}
\item{_Italic_ item}
\item{Item with __nested _italic_ text__}
\end{itemize}
And, if I run the program again on that output, I get:
\begin{itemize}
\item{item}
\item{item}
\item{\textit{Italic} item}
\item{Item with nested \textit{italic} text}}
\end{itemize}
Which is the expected result, But it is supposed to do it in one run.
I want to know if it is possible to indicate Flex to run yylex() again on the output. Reading the documentation I've found something about Reentrant C Scanners and Multiple Input Buffers, but I do not know if that would solve my problem.
What is the best solution? Reentrant scanners, multiple Input buffers, or something more simpler?
I also thought on implementing the function yywrap to tell lex launch the scanner again, but with no luck:
int yywrap(){
if (first_run == 1){
first_run++;
yyin = fopen ("/tmp/out1", "rt");
yyout = fopen("salida", "wt");
if (yyin == NULL) {
printf ("El fichero no se puede abrir\n");
exit (-1);
}
if (yyout == NULL) {
printf ("El fichero no se puede abrir\n");
exit (-1);
}
yyrestart(yyin);
return 0;
} else {
return 1;
}
}
Here is my code:
/*----- Sección de Declaraciones --------------*/
%option case-insensitive
%option debug
%option verbose
%{
#include<stdio.h>
#include<string.h>
int from_italic_text = 0; /* Para saber si venimos de una italic anidada en la bold*/
int from_bold_text = 0;
%}
/* Primitives */
word .+
scstrong "__"|"**"
scem "_"|"*"
list ^"* "|"- "
%x IN_MARKDOWN_LIST
%x BOLD_TEXT_NESTED_ITALIC ITALIC_TEXT
%x BOLD_TEXT ITALIC_TEXT_NESTED_BOLD
%%
/*----- Sección de Reglas ----------------*/
{list} {BEGIN(IN_MARKDOWN_LIST);fprintf(yyout, "\\begin{itemize}\n");}
<IN_MARKDOWN_LIST>{
^\n fprintf(yyout, "\\end{itemize}\n\n");BEGIN(INITIAL); /* si volvemos a detectar línea vacia, hemos acabado el itemize, o no era nada y salimos */
^"* "|"- " /* Eliminar la sintáxis de itemize en markdown */
[^"*"\-\n]+ fprintf(yyout, "\t\\item{%s}\n", yytext); /* Éste es el texto que compone cada línea del itemize */
\n yylineno++;BEGIN(IN_MARKDOWN_LIST); /* Si detectamos salto de línea, aumentar el número de línea, y seguimos comprobando dentro de IN_MARKDOWN_LIST buscando más items*/
}
{scstrong} { BEGIN(BOLD_TEXT_NESTED_ITALIC); /* Comienzo de un strong __....*/}
<BOLD_TEXT_NESTED_ITALIC>{
"__" fprintf(yyout, "}");BEGIN(INITIAL); // Eat the end and exit
"_" BEGIN(ITALIC_TEXT); // Hay otro elemento anidado, un italic, pasamos a procesarlo
[^_\n]* {
if (from_italic_text)
fprintf(yyout, "%s", yytext); // Texto a continuación del italic
else
fprintf(yyout, "\\textbf{%s", yytext);
}
\n BEGIN(INITIAL);
}
<ITALIC_TEXT>{
[^_\n]* fprintf(yyout, "\\textit{%s", yytext);
"_" fprintf(yyout, "}"); BEGIN(BOLD_TEXT_NESTED_ITALIC); from_italic_text = 1; /* Llegado al último _, cerramos }, volvemos al stado BOLD_TEXT y ponemos from_italic_text a 1 para saber que estuvimos aquí, y no cerra antes de tiempo el \textbf*/
}
{scem} { BEGIN(ITALIC_TEXT_NESTED_BOLD); /* Comienzo de un strong __....*/}
<ITALIC_TEXT_NESTED_BOLD>{
"_" fprintf(yyout, "}"); BEGIN(INITIAL); // Eat the end and exit
"__" BEGIN(BOLD_TEXT); // Hay otro elemento anidado, un italic, pasamos a procesarlo
[^_\n]* {
if (from_bold_text)
fprintf(yyout, "%s", yytext); // Texto a continuación del italic
else
fprintf(yyout, "\\textit{%s", yytext);
}
\n BEGIN(INITIAL);
}
<BOLD_TEXT>{
[^_\n]* fprintf(yyout, "\\textbf{%s", yytext);
"__" fprintf(yyout, "}"); BEGIN(ITALIC_TEXT_NESTED_BOLD); from_bold_text = 1; /* Llegado al último _, cerramos }, volvemos al stado BOLD_TEXT y ponemos from_italic_text a 1 para saber que estuvimos aquí, y no cerra antes de tiempo el \textbf*/
}
.|\n {ECHO;}
%%
/*----- Sección de Procedimientos --------*/
int main (int argc, char *argv[]) {
if (argc == 2) {
yyin = fopen (argv[1], "rt");
if (yyin == NULL) {
printf ("El fichero %s no se puede abrir\n", argv[1]);
exit (-1);
}
} else
yyin = stdin;
yyout = fopen("/tmp/out1", "wt");
if (yyout == NULL) {
printf ("El fichero %s no se puede abrir\n", argv[1]);
exit (-1);
}
yylex ();
return 0;
}

Instead of doing multiple traversals you do it with a single traversal and stacks:
%option stack
and change BEGIN state with
yy_push_state(STATE) // ... push current-state; BEGIN STATE
yy_pop_state // instead of BEGIN INITIAL we "return" to prev. state
This way easily have nested commands
{list} { yy_push_state(IN_MARKDOWN_LIST);fprintf(yyout, "\\begin{itemize}\n");}
<IN_MARKDOWN_LIST>{
^\n { yy_pop_state(); fprintf(yyout, "\\end{itemize}\n\n");
"__" { yy_push_state(BOLD); fprintf(yyout, "\\textbf{");
"_" { yy_push_state(ITALIC); fprintf(yyout, "\\textit{");
...
}
<ITALIC>{
"_" { yy_pop_state(); fprintf(yyout, "}"); }
....
. { fprintf(yyout, "%s",yytext);}
}

I finally came out with a solution. I do not know if it is the best, but it worked. I implemented yywrap like this:
int yywrap(){
if (first_run == 1){
first_run++;
fclose(yyout);
fclose(yyin);
yyin = fopen ("/tmp/out", "rt");
yyout = fopen("salida", "wt");
if (yyin == NULL) {
printf ("El fichero no se puede abrir\n");
exit (-1);
}
if (yyout == NULL) {
printf ("El fichero no se puede abrir\n");
exit (-1);
}
return 0;
} else {
return 1;
}
}
int main (int argc, char *argv[]) {
yyin = fopen (argv[1], "rt");
// ...
yyout = fopen("/tmp/out", "wt");
// .....
yylex();
}

Related

NumberFormat - Currency

I have a problem with my code.
I send a number but the format does not working.
My code is the next.
class SetValueClass extends HelperClass {
SetValueClass() : super();
String transformValue({
required double number,
bool? pasa,
}) {
number = 27126677097.04;
SuffixOptions suffixOptions = getSuffixObject(number);
if (pasa != null && pasa) {
print(number);
print(suffixOptions.name);
print(suffixOptions.format);
print(suffixOptions.number);
print(suffixOptions.suffix);
}
final numberFormat = NumberFormat.currency(
locale: 'es_CO',
// customPattern: '',
symbol: suffixOptions.suffix,
);
numberFormat.maximumFractionDigits = suffixOptions.format['maximumFractionDigits']!;
numberFormat.minimumFractionDigits = suffixOptions.format['minimumFractionDigits']!;
return numberFormat.format(number);
}
}
The final result i want, is parse 27126677097.04 to 27,127 MM, but y received this...
27.126.677.097,04 MM
The symbol is working successfully, but, ¿how can i compact this number and return 27,127 MM?
Note: The locale es_CO is the code of Colombia.
Thanks!
After some research, I realized that the es_CO did not work the way I needed it to, so I decided to go with the following solution.
Create a function.
String _defineValue({required number}) {
/**
* Valor en el rango de cuatrillones.
* (C)
*/
if (number > 1e+24) {
return "${(number / 1e+24).toStringAsFixed(2)} C";
}
/**
* Valor en el rango de miles de trillones.
* (MT)
*/
if (number > 1e+21) {
return "${(number / 1e+21).toStringAsFixed(3)} MT";
}
/**
* Valor en el rango de trillones.
* (T)
*/
if (number > 1e+18) {
return "${(number / 1e+18).toStringAsFixed(2)} T";
}
/**
* Valor en el rango de miles de billones.
* (MB)
*/
if (number > 1e+15) {
return "${(number / 1e+15).toStringAsFixed(3)} MB";
}
/**
* Valor en el rango de billones.
* (MB)
*/
if (number > 1e+12) {
return "${(number / 1e+12).toStringAsFixed(2)} B";
}
/**
* Valor en el rango de miles de millones.
* (MM)
*/
if (number > 1e+9) {
return "${(number / 1e+9).toStringAsFixed(3)} MM";
}
/**
* Valor en el rango de millones.
* (M)
*/
if (number > 1e+6) {
return "${(number / 1e+6).toStringAsFixed(2)} M";
}
/**
* Valor en el rango de inferior
*/
return "${(number / 1).toStringAsFixed(0)}";
}
This function gets a number and return a String with the logic required in my case.

How do i use an arduino controller and a keyboard at the same time?

How do I use a controller and keyboard at the same time?
So I use an Arduino as my controller using ReadByte() as my input
Here is my script for my player
void Start()
{
controller = GetComponent<Controller2D>(); // Je krijgt toegang tot de script Controller2D
sp.DtrEnable = true;
sp.ReadTimeout = 100;
sp.Open(); // Uw serialpoort openen
}
void Update()
{
if (sp.IsOpen) // Als uw serialpoort open is
{
try
{
print(sp.ReadByte()); // Ga je de inkomende waarde lezen
}
catch (System.Exception) { }
}
if (controller.collisions.above || controller.collisions.below) // Als je een botsing hebt van boven of beneden dan ga je stoppen met springen
{
moveDistance.y = 0;
}
if (Input.GetKeyDown(KeyCode.Space) || sp.ReadByte() == 1 && controller.collisions.below) // Als je op spatie drukt en als je op een platform staat dan ga je boven springen
{
moveDistance.y = jumpDistance; // Je gaat springen langs de y-as
//moveDistance.x = 0; // Als je alleen springt dan ga je loodrecht boven en niet schuin
}
Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); // Je neemt de Horizontal en vertical inputs van de unity zelf
if (sp.ReadByte() == 2) // Als je de 2de drukknop indrukt
{
moveDistance.x = -moveSpeed ; // Ga je links bewegen
}
if (sp.ReadByte() == 3) // Als je de 3de druknop indrukt
{
moveDistance.x = moveSpeed; // Ga je rechts bewegen
}
moveDistance.x = input.x * moveSpeed; // Door input kan je nu links of rechts bewegen met de pijlen
moveDistance.y += gravity * Time.deltaTime; // Je valt met een zwaartekracht dus je gaat sneller en sneller vallen.
controller.Move(moveDistance * Time.deltaTime); // Leest de input
}
Normally I would want to have both controller and keyboard as my inputs but after I run this game I immediatly get a
TimeoutException: the operation has timed out
error but I can use the Arduino as inputs but it's just the keyboard that gets disabled for some reason
Might be the cause of the error not sure but in general I would not use sp.ReadByte() repeatedly but only once, store the value and compare that:
void Update()
{
byte arduinoInput = 0;
if (sp.IsOpen) // Als uw serialpoort open is
{
try
{
arduinoInput = sp.ReadByte();
print(arduinoInput); // Ga je de inkomende waarde lezen
}
catch (System.Exception) { }
}
if (controller.collisions.above || controller.collisions.below) // Als je een botsing hebt van boven of beneden dan ga je stoppen met springen
{
moveDistance.y = 0;
}
if (Input.GetKeyDown(KeyCode.Space) || arduinoInput == 1 && controller.collisions.below) // Als je op spatie drukt en als je op een platform staat dan ga je boven springen
{
moveDistance.y = jumpDistance; // Je gaat springen langs de y-as
//moveDistance.x = 0; // Als je alleen springt dan ga je loodrecht boven en niet schuin
}
Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); // Je neemt de Horizontal en vertical inputs van de unity zelf
if (arduinoInput == 2) // Als je de 2de drukknop indrukt
{
moveDistance.x = -moveSpeed ; // Ga je links bewegen
}
if (arduinoInput == 3) // Als je de 3de druknop indrukt
{
moveDistance.x = moveSpeed; // Ga je rechts bewegen
}
moveDistance.x = input.x * moveSpeed; // Door input kan je nu links of rechts bewegen met de pijlen
moveDistance.y += gravity * Time.deltaTime; // Je valt met een zwaartekracht dus je gaat sneller en sneller vallen.
controller.Move(moveDistance * Time.deltaTime); // Leest de input
}
The errors are probably thrown for frames when the port is not open yet bt you already tried to read or simply caused by the multiple access.

not /n in scanf but program still waits

I've read on here that the /n in scanf makes the program wait for another input. my program however does not have a /n in scanf but it still waits for another input after i enter a number. Not sure why.
#include <stdio.h>
int main()
{
int inputNumber, index = 2, lowestPrime = 1, number = 1;
printf("Enter an integer: ");
scanf("%d", &inputNumber);
if(scanf("%d", &inputNumber) != 1)
{
printf("Invalid input");
return 1;
}
else
{
printf(" The prime factorization of %d is",inputNumber);
while(inputNumber > lowestPrime)
{
if(inputNumber % index != 0)
{
index += 1;
}
else
{
inputNumber = (inputNumber / index);
printf(" %d", index);
}
}
}
return 0;
}
You're calling scanf twice here, once for the original call and once in your if statement. Replace the statement inside the if parenthesis by
if (inputNumber!= 1)
and you should be fine!

Invoke not working Unity

Can you tell me what's wrong in this piece of code? It does not call the Invoke function
public class ReazioneBonus : MonoBehaviour {
void OnTriggerEnter(Collider collider){
string nomeBonus;
if(collider.gameObject.name.Contains("Pallina")){
nomeBonus = gameObject.name;
Debug.Log("bonus colpito");
Debug.Log("il nome del bonus è " + nomeBonus);
if(nomeBonus == "PaddleLungo(Clone)"){ //Allunga il paddle per 5 secondi
Debug.Log("attivazione Paddle Lungo");
Destroy(gameObject);
Debug.Log("bonus colpito da " + Pallina.ultimoGiocatoreToccato);
if(Pallina.ultimoGiocatoreToccato.name == "AvversarioRosso" || Pallina.ultimoGiocatoreToccato.name == "AvversarioVerde"){
Debug.Log("giocatore riconosciuto");
AllungaPaddleVerticale();
Invoke ("RipristinaPadVerticale", 5f); //non chiama la funzione
}else if(Pallina.ultimoGiocatoreToccato.name == "AvversarioBlu" || Pallina.ultimoGiocatoreToccato.name == "AvversarioGiallo"){
Debug.Log("giocatore riconosciuto");
AllungaPaddleOrizzontale();
Invoke ("RipristinaPadOrizzontale", 5f); //non chiama la funzione
}
}
}
}
void AllungaPaddleVerticale(){
Pallina.ultimoGiocatoreToccato.transform.localScale += new Vector3(3F, 0, 0);
}
void AllungaPaddleOrizzontale(){
Pallina.ultimoGiocatoreToccato.transform.localScale += new Vector3(0, 0, 3F);
}
void RipristinaPadVerticale(){
Debug.Log("ripristino il paddle");
Pallina.ultimoGiocatoreToccato.transform.localScale += new Vector3(-3F, 0, 0);
}
void RipristinaPadOrizzontale(){
Debug.Log("ripristino il paddle");
Pallina.ultimoGiocatoreToccato.transform.localScale += new Vector3(0, 0, -3F);
}
}
You destroy the gameObject of that monobehavior:
Destroy(gameObject);
How would these methods be invoked if the monobehavior itself is already destroyed?
When you destroy a GameObject all attached MonoBehaviours' active invokes are cancelled. This to prevent bad references.
Simply destroy the GameObject after your invokes are complete:
public class ReazioneBonus : MonoBehaviour {
void OnTriggerEnter(Collider collider){
string nomeBonus;
if(collider.gameObject.name.Contains("Pallina")){
nomeBonus = gameObject.name;
Debug.Log("bonus colpito");
Debug.Log("il nome del bonus è " + nomeBonus);
if(nomeBonus == "PaddleLungo(Clone)"){ //Allunga il paddle per 5 secondi
Debug.Log("attivazione Paddle Lungo");
Debug.Log("bonus colpito da " + Pallina.ultimoGiocatoreToccato);
if(Pallina.ultimoGiocatoreToccato.name == "AvversarioRosso" || Pallina.ultimoGiocatoreToccato.name == "AvversarioVerde"){
Debug.Log("giocatore riconosciuto");
AllungaPaddleVerticale();
Invoke ("RipristinaPadVerticale", 5f); //non chiama la funzione
}else if(Pallina.ultimoGiocatoreToccato.name == "AvversarioBlu" || Pallina.ultimoGiocatoreToccato.name == "AvversarioGiallo"){
Debug.Log("giocatore riconosciuto");
AllungaPaddleOrizzontale();
Invoke ("RipristinaPadOrizzontale", 5f); //non chiama la funzione
}
}
}
}
void AllungaPaddleVerticale(){
Pallina.ultimoGiocatoreToccato.transform.localScale += new Vector3(3F, 0, 0);
}
void AllungaPaddleOrizzontale(){
Pallina.ultimoGiocatoreToccato.transform.localScale += new Vector3(0, 0, 3F);
}
void RipristinaPadVerticale(){
Debug.Log("ripristino il paddle");
Pallina.ultimoGiocatoreToccato.transform.localScale += new Vector3(-3F, 0, 0);
Destroy(gameObject);
}
void RipristinaPadOrizzontale(){
Debug.Log("ripristino il paddle");
Pallina.ultimoGiocatoreToccato.transform.localScale += new Vector3(0, 0, -3F);
Destroy(gameObject);
}
}

Lex Program to check for comment lines

Could anyone please help me in writing a LEX program to check and count comment lines in a C program. I have searched for it everywhere and failed to get the complete code.
comment lines are of the form
%%
{START} {whatever symbols,alphanumerics and letters} {END}
%%
START symbol can be // or /* in C.
END symbol is */
If it is "//" any other symbol can follow it in the LINE including a second occurances of // (which is ignored).
IF it is " /* " it will find the next immediate match for " */ " and all the rest of the patterns that appear in between is matched(This matching may include blank spaces,tabs ,"//" and " /* " in it)
Here is a sample code to do it
`
%{
#include<stdio.h>
int c=0;
%}
START "/*"
END "*/"
SIMPLE [^*]
SPACE [ \t\n]
COMPLEX "*"[^/]
%s newstate
%%
"//"(.*[ \t]*.*)*[\n]+ {c++; fprintf(yyout," ");}
{START} {yymore();BEGIN newstate;}
<newstate>{SIMPLE} {yymore();BEGIN newstate;}
<newstate>{COMPLEX} {yymore();BEGIN newstate;}
<newstate>{SPACE} {yymore();BEGIN newstate;}
<newstate>{END} {c++;fprintf(yyout," ");BEGIN 0;}
%%
main()
{//program to remove comment lines
yyin=fopen("file4","r");
yyout=fopen("fileout4","w");system("cat file4");
yylex();system("cat fileout4");
printf("no.of comments=%d",c);
fclose(yyin);
fclose(yyout);
}
`
The input file "file4" is below
/* #include <stdlib.h>
{}.#All nonsense symbols */
//another comment
int main{}
{/**/
printf("hello");
/* comment inside// comment is ignored */
//how about//this?
/* now we /* try this */ */
printf("COOL!!");
return (0);
}
It gives the following output which is stored in "fileout4" `
int main{}
{
printf("hello");
*/
printf("COOL!!");
return (0);
}
`
The number of comment lines in the above program is 6.
You can maintain a boolean variable which keeps track of whether the line you're parsing is inside a multi-line comment or not.
%{
#include <stdio.h>
#include <stdbool.h>
int comment_lines = 0;
bool in_comment = false;
%}
%%
"/*".*\n { in_comment = true; ++comment_lines; }
.*"*/"\n { in_comment = false; ++comment_lines; }
"//".*\n { ++comment_lines; }
.*\n {
if (in_comment) {
++comment_lines;
} else {
fprintf(yyout, yytext);
}
}
%%
int yywrap() {
return 1;
}
int main(void) {
printf("Enter input file: ");
char filename[64];
scanf("%s", filename);
yyin = fopen(filename, "r");
printf("Enter output file: ");
scanf("%s", filename);
yyout = fopen(filename, "w");
yylex();
printf("Number of comments: %d\n", comment_lines);
}
In the above code, in_comment is used to indicate the state of the line being analyzed. If it is in a comment, the comment_lines value is incremented, otherwise the text is written to an output file given by yyout.
input file
#include <stdio.h>
/*
*
* This is a multi-line comment
*
*/
void dummy();
// main function is the entry point.
int main(void) {
/*
* Here we print a message on user's
* console.
*/
printf("Hello world\n");
// That is it.
}
output file generated after lexical analysis
#include <stdio.h>
void dummy();
int main(void) {
printf("Hello world\n");
}
Number of comments: 11
%{
#undef yywrap
#define yywrap() 1
int single=0, multiline =0;
%}
%%
"//".*"\n" {printf("%s\n", yytext); single++;}
"/*".*[\n]*.*"*/" {printf("%s\n", yytext); multiline++;}
.;
%%
int main()
{
yyin = fopen("yourfile","r");
yylex(); //calling the rules section
printf(" Single line comments = %d, multiline comments = %d", single, multiline);
fclose(yyin);
}