3

I'm validating some input; the input number should be from 1 to 255. And I try the following code. Input defined ;input DC CL60' ''

clc   input,=c'255'   
bh    loop1
clc   input,=c'1'     
bl    loop1
J     loop2 
loop1

The above validation is only working for 3 digits numbers ( from 100 to 255) But it is not working for two digit number. Could you please help me :)

GAS SAM
  • 29
  • 5
  • 1
    What architecture is this? – Nate Eldredge Jan 24 '19 at 19:19
  • I'm new for assembly ; I'm using mainframe z/os :) – GAS SAM Jan 24 '19 at 19:20
  • I wonder if there is a better tag for this than [tag:mainframe]. – Nate Eldredge Jan 24 '19 at 19:22
  • @NateEldredge: assembly + [tag:zos]` is how other IBM System/360 questions are tagged. – Peter Cordes Jan 24 '19 at 19:37
  • I suspect you'll need to provide more code than that. Especially around what input looks like, in terms of the data structure, and whether or not you're clearing any data in it. – Kevin McKenzie Jan 24 '19 at 19:47
  • @KevinMcKenzie input is the input from the job card and it is defined as input ds x3. – GAS SAM Jan 24 '19 at 19:49
  • Can you provide all JCL and the entire program? I'm not an expert in this area, but the description you provide of the problem suggests to me that when input is a one or two digit number, there is data being pulled along somehow that causes the test to fail. So one thing I'd suggest doing is looking at the input data, and the input jcl, in hex, and seeing what's there. Possibly try inputing 010 instead of 10, for example. – Kevin McKenzie Jan 24 '19 at 19:54
  • 2
    Compare Logical Character (or CLC) performs a string comparison, not a numerical comparison. – meat Jan 24 '19 at 19:54
  • 2
    When it is a 2 digit number, are you prefixing it with a 0? If it's 1 digit, do you prefix it with 2 0's? If you use the space character instead then you need to ensure that an arithmetic compare of the characters and '2' will give you what you want, since CLC is a compare logical character. My recommendation would be to 0 pad a number less than 3 digits with 0's to get it to 3 digits or alternately, convert the numbers to binary first before the comparision – mike Jan 24 '19 at 19:54
  • How is data being placed in INPUT? – zarchasmpgmr Jan 25 '19 at 03:18
  • @zarchasmpgmr I'm parsing from the job car, the data input do not have a problem . this case happen when I try to compare for Integer input ; for character comparison working . – GAS SAM Jan 25 '19 at 04:51
  • Can you provide more code to show what your doing ? Your code leaves out key questions like what is `INPUT`and how is it defined. Is the number already justified right or left and has spaces removed? – Hogstrom Jan 25 '19 at 14:49
  • @Hogstrom ,Input is defined this way, input DC CL60' ' (user defined data) . I'm parsing this value from the job car. when the server start it will read the parameters from the data sets then the main module parse the parameters from the job car. – GAS SAM Jan 26 '19 at 05:49

2 Answers2

3

A lot depends on how flexible you need to be with your "INPUT" field. For instance, if you need to process C'1 ', C' 1 ', C' 1', C'01 ', C' 01' and C'001' all the same way, then you have some extra work to do.

You have two choices in general. Either you can "normalize" your data into a three character field (in other words, make all the examples I mention above C'001'), or you can do some imaginative variable length compares to adapt to the size of the values you're trying to compare.

This will make more sense to you if you get a little deeper into how CLC works. If you look at the assembler listing of your program, you'll see the object code for the CLC you coded in hex...it'll be something like D5llsaaatbbb where:

  • "D5" is the opcode - CLC
  • "ll" is the length of the compare you're doing
  • "s" is the first operand base register
  • "aaa" is the first operand displacement
  • "t" is the second operand base register
  • "bbb" is the second operand displacement

So if your input field is indeed DC CL60' ', and it's stored at 100 bytes off of register 10 and the literal (=C'whatever') is 40 bytes off of register 12 you'd see D53BA064C028. Code enough assembler and you'll be reading these things like they were English. :)

As one of the other posters points out, the assembler defaults the length to the length of the first operand, so right off the bat, you have a problem since the comparison you're doing (clc input,=C'1') causes the assembler to generate a 60 byte compare, even though the second operand is only one byte long. If you wanted to do it this way, you'd need do code it as clc input,=CL60'1 ...'. This is why it's usually more convenient to either code the instruction "backwards" (as in clc =C'1',input) or explicitly specify the length (as in clc input(1),=C'1') so that you don't inadvertently run past the end of the field you're comparing against.

Next issue you run into is making the compare a variable length one. Many times, you'll want to figure out how many digits you have, and then compare this many digits rather than the length of the field. For instance, you might look at data coded as ' 1' and decide to skip the blanks and just check the field as a one-byte value. For this sort of thing, the execute (EX) instruction is your friend - it gives you an easy way to have a variable-length comparison.

Let's say you figure out that the user entered a single byte and thus you want a single byte CLC. Assuming the length you want is in a register, the code would look like this:

* Assume you have the length in R1
       BCTR R1,0         Don't forget lengths are 0-relative (00 = 1 byte, FF=256)
       EX   R1,MYCLC     Do the comparison using the length in R1
       J    *+10         Skip over the CLC instruction
MYCLC  CLC  INPUT(0),PATTERN       Executed instruction

The EX instruction uses the first operand to update the target instruction, and then executes it. In the example, EX uses the value in R1 to set the length in the CLC, giving you a variable-length comparison. Note the length of 0 - the object code would be D500 in this case, EX "OR's" the low-order bits of R1 with the 00 to give you the length you want. Simple, right?

The last piece of the puzzle is some parsing on your INPUT field, assuming it's a free form field that can contain things like blanks. A common need for this is finding the initial non-blank field in a longer string...here, translate-and-test (TRT) is your friend. I won't bore you with the details, but it gives you a single instruction that can scan a field to find any particular character - a non-blank or a blank, for example. A pair of TRT instructions can help you find the start and end of any delimited string, similar to strchr() in C (if you're a C programmer). A little subtraction to get some lengths, and you're all set to do what you need with the variable-length comparison explained above.

As you code more assembler, you'll figure out all the little tricks that make these tasks easier. For example, a "feature" of EBCDIC is that the hex encoding of digits are at the top of the scale: F0 to F9. That means that in many simple apps, you don't really have to deal with your case of "higher than 999" because all the alpha and typical symbols are lower than a C'0'...just checking for not less than a 0 is usually adequate for character data.

Anyway, a few of the hints here should get you going, and I'm sure you'll have no trouble getting the result you expect with a little more research.

Valerie R
  • 1,769
  • 9
  • 29
  • Anytime - I believe the world needs more mainframe assembler programmers, so happy to help. Sometime, upvote my response if it's been helpful. – Valerie R Jan 29 '19 at 14:06
  • I did but I'm getting , Thanks for the feedback! Votes cast by those with less than 15 reputation are recorded, but do not change the publicly displayed post score. :D poor me – GAS SAM Jan 29 '19 at 14:36
  • Well, I think you'll pretty quickly earn the reputation - just keep asking and responding to questions! – Valerie R Jan 29 '19 at 15:16
1

When the assembler generates the length for the comparison it is based on the first operand. You do not show this in the code but my assumption it is something like

INPUT DS CL3

In this case, the instruction CLC input,=c'1' is comparing a three byte field with 1 character literal. So, you are comparing a three byte area to a three byte area that is a 1 character value so the second two bytes are undefined.

If you want to base the comparison based on the literal you could do this instead:

         clc   =c'255',input   
         bh    loop1
         clc   =c'1',input     
         bl    loop1
         J     loop2 
loop1

There are better approaches though. You could convert the input to a packed decimal format and then do a numerical comparison.

For instance, assume this is your code:

             PACK DecimalInput,Input  
             CP   DecimalInput,=P'255'  
             BH   TooHigh  
             CP   DecimalInput,=P'1'  
             BL   TooLow
JustRight    DS  0H


DecimalInput DS   PL3 
Input        DS   CL3  

Of course, you'll need to validate they are numbers or you'll end up with an S0C7.

Hogstrom
  • 3,581
  • 2
  • 9
  • 25
  • 1
    It sounds like you need to parse the input, isolate the numbers and perform the comparion. If you could show some examples of what some input looks like it would help us to help you – Hogstrom Jan 26 '19 at 12:51
  • @Hogstorm I think the problem is in the input data , for example when I pass 99 it is not working , but when I did 099 it is working. could you please help me how I append 0 in front of the input data – GAS SAM Jan 26 '19 at 13:41
  • Your input data needs to be edited during data entry. Editing and sanity-checking data is critical, otherwise you have the old GIGO aphorism. Otherwise you need to edit the data yourself. It’s more work, but you can test the second character for a space (cli input+1,c’ ‘) and the third character (input+2) for a space, with appropriate logic and correct PACK instructions. – zarchasmpgmr Jan 27 '19 at 22:49