Lex: Saving entire string using starting condition and state transition - conditional-statements

I'm wondering if it's possible to save the entire input from the start condition to the final state in lex.
For example:
%x START
%%
"XXX" BEGIN START;
<START>.
<START>"YYY" {printf("%s", yytext);}
Will print YYY if I enter something like XXX some chars YYY, but I'd like it to print XXX some chars YYY. Is there a way to do this in lex?

Call yymore() from every action in the start condition except the last one. yymore() means that there is more token to come; it causes the scanner to not reset the token
start point.

Related

EOL error - Escape Newline Characters in a Python String

I wish to hand chunks of text to an API. However, I cant as python wont let me handle the text if I try saving as a variable. How do I do it? Thank you
prompt = (f"xxxx
xxxx
xxxxx
xxxx
xxxx")
I tried code below to overcome the EOL error but it didnt work. I want to do it automatically not manually add backslashes as prompt is text which will change for input to an api. This made no difference
def escape_newline(string):
return string.replace("\n", "\\n")
prompt= scape_newline(prompt)
print (prompt)
This comes up with:
prompt = (f"xxxx
^
SyntaxError: EOL while scanning string literal
Use triple strings instead of single ones. That allows for strings to take place over multiple lines :)
prompt = (f"""xxxx
xxxx
xxxxx
xxxx
xxxx""")
print(prompt)

How to read elements from a line in VHDL?

I'm trying to use VHDL to read from a file that can have different formats. I know you're supposed to use the following two lines of code to read a line at a time, the read individual elements in that line.
readline(file, aline);
read(aline, element);
However my question is what will read(aline, element) return into element? What will it return if the line is empty? What will it return if I've used it let's say 5 times and my line only has 4 characters?
The reason I want to know is that if I am reading a file with an arbitrary number of spaces between valid data, how do I parse this valid data?
The file contains ASCII characters separated by arbitrary amounts of white space (any number of spaces, tabs, or new lines). If the line starts with a # that line is a comment and should be ignored.
Outside of these comments, the first part of the file contains characters that are only letters or numbers in combinations of variable size. In other words this:
123 ABC 12ABB3
However, the majority of the file (after a certain number of read words) will be purely numbers of arbitrary length, separated by an arbitrary amount of white space. In other words, the second part of the file is this:
255 0 2245 625 430
2222 33 111111
and I must be able to parse these numbers (and interpret them as such) individually.
As mentioned in the comments, all the read procedures in std.textio and ieee.std_logic_textio skip over leading spaces apart from the character and string versions (because a space is as much a character as any other).
You can test whether a line variable (the buffer) is empty like this:
if L'length > 0 then
where L is your line variable. There is also a set of overloaded read procedures with an extra status output:
procedure read (L : inout LINE;
VALUE: out <type> ;
GOOD : out BOOLEAN);
The extra output - GOOD - is true if the read was successful and false if it wasn't. The advantage of these if that the read is unsuccessful, the simulation does not stop (as it does with the regular procedures). Also, with the versions in std.textio, if the read is unsuccessful, the read is non-destructive (ie whatever you were trying to read remains in the buffer). This is not the case with the versions in ieee.std_logic_textio, however.
If you really do not know what format you are trying to read, you could read the entire line into a string, like this:
variable S : string(1 to <some big number>);
...
readline(F, L);
assert L'length < S'length; -- make sure S is big enough
S := (others => ' '); -- make sure that the previous line is overwritten
if L'length > 0 then
read(L, S(1 to L'length);
end if;
The line L is now in the string S. You can then write some code to parse it. You may find the type attribute 'value useful. This converts a string to some type, eg
variable I : integer;
...
I := integer'value(S(12 to 14));
would set integer I to the value contained in elements 12 to 14 of string S.
Another approach, as suggested by user1155120 below, is to peek at the values in the buffer, eg
if L'length > 0 then -- check that the L isn't empty, otherwise the next line blows up
if L.all(1) = '#' then
-- the first character of the line is a '#' so the line must be a comment

AutoIt ControlSend() function occasionally replaces hyphens with underscores

I'm using an AutoIt script to automate interaction with a GUI, and part of the process involves using the ControlSend() function to place a file path into a combo box. The majority of the time, the process works properly, but occasionally ( ~ 1/50 calls to the function? ) a single hyphen in the filepath is replaced with an underscore. The script is to be run unsupervised for bulk data processing, and such an error typically results in a forced-focus popup that screams "The file could not be found!" and halts further processing.
Unfortunately, due to the character limit of the combo box, I cannot supply all 16 arguments with a single call, and I am forced to load each of the images individually using the following for-loop:
;Iterate through each command line argument (file path)
For $i = 1 To $CmdLine[0]
;click the "Disk" Button to load an image from disk
ControlClick("Assemble HDR Image", "", "[CLASS:Button; TEXT:Disk; Instance:1]")
;Give the dialogue time to open before entering text
Sleep(1000)
;Send a single file path to the combo box
ControlSend("Open", "" , "Edit1", $CmdLine[$i])
;"Press Enter" to load the image
Send("{ENTER}")
Next
In an errant run, the file path
C:\my\file\path\hdr_2016-04-22T080033_00_rgb
^Hyphen
is converted to
C:\my\file\path\hdr_2016_04-22T080033_00_rgb
^Underscore
Due to the existence of both hyphens and underscores in the file name, it is difficult to perform a programmatic correction (e.g. replace all underscores with hyphens).
What can be done to correct or prevent such an error?
This is both my first attempt at GUI automation and my first question on SO, and I apologize for my lack of experience, poor wording, or deviations from StackOverflow convention.
Just use ControlSetText instead of ControlSend as it will set the complete Text at once and won't allow other keystrokes (like Shift) to interfere with the many virtual keystrokes that the Send-function fires.
If the hyphen is the problem and you need to replace it, you can do so:
#include <File.au3>
; your path
$sPath = 'C:\my\file\path'
; get all files from this path
$aFiles = _FileListToArray($sPath, '*', 1)
; if all your files looks like that (with or without hyphen), you can work with "StringRegExpReplace"
; 'hdr_2016-04-22T080033_00_rgb'
$sPattern = '(\D+\d{4})(.)(.+)'
; it means:
; 1st group: (\D+\d{4})
; \D+ one or more non-digit, i.e. "hdr_"
; \d{4} digit 4-times, i.e. "2016"
; 2nd group: (.)
; . any character, hyphen, underscore or other, only one character, i.e. "~"
; 3rd group: (.+)
; . any character, one or more times, i.e. "22T080033_00_rgb"
; now you change the filename for all cases, where this pattern matches
Local $sTmpName
For $i = 1 To $aFiles[0]
; check for pattern match
If StringRegExp($aFiles[$i]) Then
; replace the 2nd group with underscore
$sTmpName = StringRegExpReplace($aFiles[$i], $sPattern, '\1_\3')
FileMove($sPath & '\' & $aFiles[$i], $sPath & '\' & $sTmpName)
EndIf
Next

Printing Expected Token Type XXX when a parsing error occurs

I would like to be able to print this error message using Ragel
=> Parsing error found at position line:col, Integer expected instead.
Is that possible with Ragel?
Best regards
I haven't gotten too far into error handling in Ragel just yet, but I would expect that if you use the error action embedding operators as specified in section 3.2.3 of the Ragel 6.9 Guide, that would override the default message.
You can get the line number by incrementing a counter at each newline, and get the column by taking the current position and subtracting the position of the previous newline, something like this:
newline = '\n' %{ ++lineCounter; linePosition = p; }
action ErrorHandler {
column = p - linePosition + 1;
// Print error message here using lineCounter and column
}
main := (allsortsofstuff | newline)* <>err(ErrorHandler);
Of course, the above may require a bit of tweaking based on exactly what you're doing, but at least it's a starting point.

Limitting character input to specific characters

I'm making a fully working add and subtract program as a nice little easy project. One thing I would love to know is if there is a way to restrict input to certain characters (such as 1 and 0 for the binary inputs and A and B for the add or subtract inputs). I could always replace all characters that aren't these with empty strings to get rid of them, but doing something like this is quite tedious.
Here is some simple code to filter out the specified characters from a user's input:
local filter = "10abAB"
local input = io.read()
input = input:gsub("[^" .. filter .. "]", "")
The filter variable is just set to whatever characters you want to be allowed in the user's input. As an example, if you want to allow c, add c: local filter = "10abcABC".
Although I assume that you get input from io.read(), it is possible that you get it from somewhere else, so you can just replace io.read() with whatever you need there.
The third line of code in my example is what actually filters out the text. It uses string:gsub to do this, meaning that it could also be written like this:
input = string.gsub(input, "[^" .. filter .. "]", "").
The benefit of writing it like this is that it's clear that input is meant to be a string.
The gsub pattern is [^10abAB], which means that any characters that aren't part of that pattern will be filtered out, due to the ^ before them and the replacement pattern, which is the empty string that is the last argument in the method call.
Bonus super-short one-liner that you probably shouldn't use:
local input = io.read():gsub("[^10abAB]", "")