Compare strings in Forth - forth

I enter strings from the keyboard and compare them. But it never returns 0 even if the strings are equal.
CREATE word1 14 ALLOT
: .getword1 word1 14 BLANK word1 14 EXPECT ;
CREATE word2 14 ALLOT
: .getword2 word2 14 BLANK word2 14 EXPECT ;
: input_words
." " CR
." First word:" CR
.getword1
." " CR
." Second word:" CR
.getword2
word2
word1
word1 word2 compare
." " CR
.s
;
It never returns 0 for my strings:
First word:
e
Second word:
e
<1> 1
Is there something wrong with the definitions?

compare has the following stack signature ( cstr1 count1 cstr2 count2 -- n ). It requires the addresses of the string and their counts (lengths)
create word1 ," Test" \ Store counted string in word1
create word2 ," Test" \ Store counted string in word2
word1 count type Test ok
word2 count type Test ok
word1 . word2 . 4992752 4992848 ok \ addresses of word1 and word2
word1 count word2 count .s compare
DATA STACK
top
4 0000:0004 \ count2
4992849 004C:2F51 \ address word2 + 1
4 0000:0004 \ count1
4992753 004C:2EF1 \ address word1 + 1
ok-1
. 0 ok
Further comparisons
char S word1 1+ c! ok \ Change the T in word1 to an S
word1 count type Sest ok
word1 count word2 count compare . -1 ok
char R word2 1+ c! ok \ Change the T in word1 to an R
word2 count type Rest ok
word1 count word2 count compare . 1 ok
I don't have an EXPECT word on my system to test your code but I suspect various items are left on the stack by your getwordx words that means the comparison doesn't cause an exception but doesn't do the comparisons you expect.
Edit: An answer with EXPECT implemented.
\ Creating ANS forth EXPECT. I have ACCEPT not EXPECT in my Forth
CELL USER SPAN
: EXPECT \ addr ct --
ACCEPT SPAN ! ;
\ Answer to question
: getword \ addr ct --
2DUP BL FILL \ Fill addr for count with blanks
EXPECT ; \ Refill addr with characters typed at the prompt.
CREATE word1 14 ALLOT
CREATE word2 14 ALLOT
: wtype \ addr -- ;
14 -TRAILING TYPE ;
: input_words \ ;
CR ." First Word : " word1 14 getword
CR ." Second Word : " word2 14 getword
CR word1 wtype 5 SPACES word2 wtype
CR word1 14 word2 14 compare .
;
As both buffers are filled with blanks for any unused characters the comparison is still valid.
input_words
First Word : Test
Second Word : Test
Test Test
0 ok
input_words
First Word : Rest
Second Word : Test
Rest Test
-1 ok

Related

Prepend match number to output match lines of grep?

Say I have this file, test.log:
blabla test test
20 30 40
hello world
100 100
34 506 795
blabla test2
50 60 70
hello
10 10
200 200
blabla test BB
30 40 50
100 100
20 20 20 20
I would like to print all lines with blabla in them, the line after that - with the match number prepended.
Without match number, it is easy:
$ grep -A1 "blabla" test.log
blabla test test
20 30 40
--
blabla test2
50 60 70
--
blabla test BB
30 40 50
With a prepended match number, it would look like this:
1: blabla test test
1: 20 30 40
--
2: blabla test2
2: 50 60 70
--
3: blabla test BB
3: 30 40 50
The tricky part is, I want to preserve the match number, regardless if I just grep for a single line match, or with context (X lines after or before the match).
Is there an easy way to do this? If I could do a format specifier for the number, as in %03d, even better - but just a usual number would be fine too...
Something like
grep -A1 blahblah test.log | awk -v n=1 '$0 == "--" { n += 1; print; next }
{ printf("%03d: %s\n", n, $0) }'
Perl to the rescue!
perl -ne '/blabla/ and print ++$i, ":$_" and print "$i:", scalar <>' -- file
-n reads the input line by line
each line is read into the special variable $_
the diamond operator <> reads the next line from the input file
scalar makes it read just one line, not all the remaining ones
the variable $i is incremented each time blabla is encountered and is prepended to each output line.
Your specification doesn't handle the case when two blablas are present on adjacent lines.
To format the numbers, use sprintf:
perl -ne 'if (/blabla/) { $f = sprintf "%03d", ++$i; print $f, ":$_"; print "$f:", scalar <>}'

select a row except all the other rows based on some condition psql

Consider this scenario:
There is a table T (name,habit) where combination of name and habit is the primary key for the table T.
Suppose the data is as follows:
name | habit
a1 | smoking
a1 | drinking
a2 | sleeping
a3 | jogging
a2 | jogging
a4 | sleeping
Now I want to select names which have all the habits as unique. Here clearly a2,a3 and a4 have habits in common so they should be filtered out.
So the output should be like
OUTPUT:
name
a1
My question:
How can I do this using except in psql?
you don't need except for it:
t=# with a as (
select *,count(1) over (partition by habit)
from t
)
select distinct name
from a
where count = 1;
name
------
a1
(1 row)
schema:
t=# create table T (name text,habit text);
CREATE TABLE
Time: 14.162 ms
t=# copy t from stdin delimiter '|';
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> a1 | smoking
a1 | drinking
a2 | sleeping
a3 | jogging
a2 | jogging
a4 | sleeping>> >> >> >> >>
>> \.
COPY 6
Time: 3216.573 ms

How to remove a word that matches at the beginning of each line

I would like to ask, how could I remove lines contaning the pattern AAA at their beginning?
example:
contents of file.txt:
AAA/bb/cc/d/d/d/d/e
AAA/dd/r/t/e/q/e/tg
AAA/uu/y/t/r/e/w/q
123 234 456 AAA/f/f/f/f/g/g
555 999 000 AAA/y/g/h/u/j/k
I would like to remove the first three lines with this type of pattern but would like to keep the last two lines.
The output of the command should be:
123 234 456 AAA/f/f/f/f/g/g
555 999 000 AAA/y/g/h/u/j/k
How could I do it with a unix command?
Thank you.
sed `/^AAA/d` file.txt
The /^AAA/ is a regular expression which matches AAA at the beginning of a line (^). d deletes the selected lines.
man sed for more information on the sed stream editor.

Display multiple lines using multiple patterns

Hope you can shed some light in one of my requirements. Let say I have file with the following entries:
ABC 123
XYZ 789
XYZ 456
ABC 234
XYZ 789
ABC 567
XYZ 789
XYZ 678
XYZ 123
Basically, I have rows ABC with X numbers of XYZ rows after it. The number of XYZ records in each ABC varies from 1 to many.
I need a shell script that will output the ABC and the corresponding XYZ based on the patterns in the 2nd column.
For example, display the ABC record with pattern 567 and the corresponding XYZ record with pattern 678.
The output should only be:
ABC 567
XYZ 678
To solve this, I use awk to massage the data into a single line, then grep on that output, then sed to revert matching entries to the original format.
awk '{ printf ($1 == "ABC" ? "\n" : " #¶# ") $0 }' file |grep 567 |sed 's/ #¶# /\n/g'
Code walk:
I used #¶# as a delimiter. Use something that won't have conflicts in your data (otherwise you'll have to deal with escaping it). Also note that your UTF8 support mileage may vary.
awk prints, without trailing line break, two things concatenated:
If we're on an ABC line, a line break (\n). Otherwise, the delimiter (#¶#).
Then the existing line ($0)
grep then runs for your query. This lets you use -f FILE_OF_PATTERNS or a collection of -e PATTERNs
sed then reverts the delimiters back to the original format
This has the advantage of going line by line. If you have tens of thousands of XYZs in a single ABC, it'll be a bit slower, but this doesn't keep anything in memory, so this should be pretty scalable.
Here is the output of the above awk command (yes, there is a leading blank line, which doesn't matter):
$ awk '{ printf ($1 == "ABC" ? "\n" : " #¶# ") $0 }' file
ABC 123 #¶# XYZ 789 #¶# XYZ 456
ABC 234 #¶# XYZ 789
ABC 567 #¶# XYZ 789 #¶# XYZ 678 #¶# XYZ 123
try this if it works for you. I hope I understood your requirement right:
awk -v p1='ABC 567' -v p2='XYZ 678'
'$0~p1{t=1;print;next}/^ABC/{t=0}$0~p2&&t' file

Why cut cannot work?

So basically I want to print out certain columns of the .data, .rodata and .bss sections of an ELF binary, and I use this command:
readelf -S hello | grep "data\|bss" | cut -f1,2,5,6
but to my surprise, the results are:
[15] .rodata PROGBITS 080484d8 0004d8 000020 00 A 0 0 8
[24] .data PROGBITS 0804a00c 00100c 000008 00 WA 0 0 4
[25] .bss NOBITS 0804a014 001014 000008 00 WA 0 0 4
which means the cut didn't work...
I don't know why and after some search online, I still don't know how to make it right, could anyone give me some help?
I would have used awk here since you can do all with one command.
readelf -S hello | awk '/data|bss/ {print $1,$2,$5,$6}'
awk will work with any blank space a separator. One space, multiple space, tabs etc.
You input is actually demited by spaces not TAB. By default cut expects TAB. This should work:
cut -d ' ' -f1,2,5,6
It specifies the delimiter as ' ' (space).

Resources